diff --git a/NuGet.config b/NuGet.config index d62ece6b60..83bc90a901 100644 --- a/NuGet.config +++ b/NuGet.config @@ -6,6 +6,7 @@ + diff --git a/eng/Baseline.Designer.props b/eng/Baseline.Designer.props index b5c8196535..0550859109 100644 --- a/eng/Baseline.Designer.props +++ b/eng/Baseline.Designer.props @@ -2,106 +2,106 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 3.1.0 + 3.1.1 - 3.0.0 + 3.0.2 - 3.0.0 + 3.0.2 - 3.1.0 + 3.1.1 - 3.1.0 + 3.1.1 - - - + + + - + - 3.1.0 + 3.1.1 - 3.1.0 + 3.1.1 - - + + - 3.1.0 + 3.1.1 - - + + - 3.1.0 + 3.1.1 - 3.1.0 + 3.1.1 - 3.1.0 + 3.1.1 - 3.1.0 + 3.1.1 - 3.1.0 + 3.1.1 - 3.1.0 + 3.1.1 - + - 3.1.0 + 3.1.1 - 3.1.0 + 3.1.1 - 3.1.0 + 3.1.1 @@ -109,39 +109,39 @@ - 3.1.0 + 3.1.1 - - - + + + - - - + + + - 3.1.0 + 3.1.1 - - + + - 3.1.0 + 3.1.1 - + - 3.1.0 + 3.1.1 - + @@ -186,273 +186,273 @@ - 3.1.0 + 3.1.1 - - - + + + - - - + + + - 3.1.0 + 3.1.1 - 3.1.0 + 3.1.1 - - + + - - + + - 3.1.0 + 3.1.1 - + - + - 3.1.0 + 3.1.1 - - - - + + + + - - - - + + + + - 3.1.0 + 3.1.1 - - + + - 3.1.0 + 3.1.1 - + - + - + - 3.1.0 + 3.1.1 - 3.1.0 + 3.1.1 - + - + - 3.1.0 + 3.1.1 - - - - - - + + + + + + - - - - - - + + + + + + - 3.1.0 + 3.1.1 - 3.1.0 + 3.1.1 - + - 3.1.0 + 3.1.1 - + - 3.1.0 + 3.1.1 - - + + - 3.1.0 + 3.1.1 - - + + - - + + - 3.1.0 + 3.1.1 - + - 3.1.0 + 3.1.1 - + - 3.1.0 + 3.1.1 - - + + - 3.1.0 + 3.1.1 - 3.1.0 + 3.1.1 - - - + + + - - - + + + - 3.1.0 + 3.1.1 - + - + - 3.1.0 + 3.1.1 - + - + - 3.1.0 + 3.1.1 - - + + - - + + - 3.1.0 + 3.1.1 - - - - + + + + - 3.1.0 + 3.1.1 - - + + - 3.1.0 + 3.1.1 @@ -460,236 +460,238 @@ - 3.1.0 + 3.1.1 - 3.1.0 + 3.1.1 - + - 3.1.0 + 3.1.1 - + - 3.1.0 + 3.1.1 - - - + + + - 3.1.0 + 3.1.1 - - - + + + - 3.1.0 + 3.1.1 - + - 3.1.0 + 3.1.1 - 3.1.0 + 3.1.1 - + - - + + - 3.1.0 + 3.1.1 - - + + - 3.1.0 + 3.1.1 - - + + - - + + - - - - + + + + - 3.1.0 + 3.1.1 - - + + - - + + - 3.1.0 + 3.1.1 - + - + - 3.1.0 + 3.1.1 - + - 3.1.0 + 3.1.1 - + - 3.1.0 + 3.1.1 - - - - + + + + - 3.1.0 + 3.1.1 - + - 3.1.0 + 3.1.1 - + - 3.1.0 + 3.1.1 - - + + - 3.1.0 + 3.1.1 - 3.1.0 + 3.1.1 - 3.1.0 + 3.1.1 - 3.1.0 + 3.1.1 - 3.1.0 + 3.1.1 - 3.1.0 + 3.1.1 - 3.1.0 + 3.1.1 - 3.1.0 + 3.1.1 - 3.1.0 + 3.1.1 - - - + + + - 3.1.0 + 3.1.1 - - - + + + - - - + + + - 3.1.0 + 3.1.1 - - + + + - - + + + \ No newline at end of file diff --git a/eng/Baseline.xml b/eng/Baseline.xml index 9a5276d729..d479dfe6ce 100644 --- a/eng/Baseline.xml +++ b/eng/Baseline.xml @@ -4,86 +4,86 @@ This file contains a list of all the packages and their versions which were rele Update this list when preparing for a new patch. --> - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/eng/Dependencies.props b/eng/Dependencies.props index 2e11857b1b..6ec858033d 100644 --- a/eng/Dependencies.props +++ b/eng/Dependencies.props @@ -147,6 +147,16 @@ and are generated based on the last package release. + + + + + + + + + + diff --git a/eng/ProjectReferences.props b/eng/ProjectReferences.props index 350c026a7d..a14d2cf642 100644 --- a/eng/ProjectReferences.props +++ b/eng/ProjectReferences.props @@ -5,143 +5,12 @@ --> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/eng/Versions.props b/eng/Versions.props index acef5287d1..664c95dbeb 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -8,8 +8,8 @@ 3 1 - 0 - 3 + 2 + 0 @@ -19,21 +19,21 @@ false preview$(PreReleasePreviewNumber) Preview $(PreReleasePreviewNumber) + + 4 + preview$(BlazorClientPreReleasePreviewNumber) $(AspNetCoreMajorVersion).$(AspNetCoreMinorVersion) + + 3.1.0 false - - true - - true + + true $(AspNetCoreMajorVersion).$(AspNetCoreMinorVersion).$(AspNetCorePatchVersion) $(VersionPrefix) - $(AspNetCoreMajorVersion).$(AspNetCoreMinorVersion).0 + $(AspNetCoreMajorVersion).$(AspNetCoreMinorVersion).2 0.3.$(AspNetCorePatchVersion) $([MSBuild]::Add(10, $(AspNetCoreMajorVersion))) @@ -62,14 +62,15 @@ --> - 1.0.0-beta.19577.5 + 1.0.0-beta.19607.3 - 3.4.0-beta4-19569-03 + 3.4.1-beta4-19614-01 - 3.1.1-servicing.19575.1 - 3.1.1-servicing.19576.9 + 3.1.2 + 3.1.2-servicing.20067.4 3.1.0 - 3.1.1-servicing.19575.1 + 3.1.2 + 3.1.2 2.1.0 1.1.0 @@ -91,7 +92,7 @@ 4.7.0 4.7.0 4.7.0 - 4.7.0 + 4.7.1 4.7.0 4.7.0 @@ -99,80 +100,80 @@ 3.2.0-preview1.20067.1 - 3.1.0-rtm.19575.5 - 3.1.0-rtm.19575.5 - 3.1.0-rtm.19575.5 - 3.1.0-rtm.19575.5 - 3.1.0-rtm.19575.5 - 3.1.0 - 3.1.0 - 3.1.0 - 3.1.0 - 3.1.0-rtm.19575.5 - 3.1.0 - 3.1.0 - 3.1.0 - 3.1.0 - 3.1.0 - 3.1.0 - 3.1.0 - 3.1.0 - 3.1.0 - 3.1.0 - 3.1.0 - 3.1.0 - 3.1.0 - 3.1.0 - 3.1.0 - 3.1.0 - 3.1.0 - 3.1.0 - 3.1.0 - 3.1.0 - 3.1.0 - 3.1.0 - 3.1.0-rtm.19575.5 - 3.1.0 - 3.1.0 - 3.1.0-rtm.19575.5 - 3.1.0 - 3.1.0 - 3.1.0 - 3.1.0 - 3.1.0 - 3.1.0 - 3.1.0 - 3.1.0 - 3.1.0 - 3.1.0 - 3.1.0 - 3.1.0-rtm.19575.5 - 3.1.0 - 3.1.0 - 3.1.0 - 3.1.0 - 3.1.0 - 3.1.0-rtm.19575.5 - 3.1.0 - 3.1.0-rtm.19575.5 - 3.1.0-rtm.19575.5 - 3.1.0 + 3.1.2-servicing.20067.6 + 3.1.2-servicing.20067.6 + 3.1.2-servicing.20067.6 + 3.1.2-servicing.20067.6 + 3.1.2-servicing.20067.6 + 3.1.2 + 3.1.2 + 3.1.2 + 3.1.2 + 3.1.2-servicing.20067.6 + 3.1.2 + 3.1.2 + 3.1.2 + 3.1.2 + 3.1.2 + 3.1.2 + 3.1.2 + 3.1.2 + 3.1.2 + 3.1.2 + 3.1.2 + 3.1.2 + 3.1.2 + 3.1.2 + 3.1.2 + 3.1.2 + 3.1.2 + 3.1.2 + 3.1.2 + 3.1.2 + 3.1.2 + 3.1.2 + 3.1.2-servicing.20067.6 + 3.1.2 + 3.1.2 + 3.1.2-servicing.20067.6 + 3.1.2 + 3.1.2 + 3.1.2 + 3.1.2 + 3.1.2 + 3.1.2 + 3.1.2 + 3.1.2 + 3.1.2 + 3.1.2 + 3.1.2 + 3.1.2-servicing.20067.6 + 3.1.2 + 3.1.2 + 3.1.2 + 3.1.2 + 3.1.2 + 3.1.2-servicing.20067.6 + 3.1.2 + 3.1.2-servicing.20067.6 + 3.1.2-servicing.20067.6 + 3.1.2 3.1.0-rtm.19565.4 - 3.1.0 - 3.1.0-preview4.19575.5 + 3.1.2 + 3.1.2-preview4.20067.6 - 3.1.0 - 3.1.0 - 3.1.0 - 3.1.0 - 3.1.0 - 3.1.0 - 3.1.0 + 3.1.2 + 3.1.2 + 3.1.2 + 3.1.2 + 3.1.2 + 3.1.2 + 3.1.2 - 3.1.0-rtm.19573.1 - 3.1.0-rtm.19573.1 - 3.1.0-rtm.19573.1 - 3.1.0-rtm.19573.1 + 3.1.2 + 3.1.2 + 3.1.2 + 3.1.2 $(MicrosoftNETCoreAppRuntimewinx64PackageVersion) + 3.1.2 @@ -264,10 +266,19 @@ $(XunitVersion) $(XunitVersion) 1.0.19249.1 + + + 3.1.2-servicing.20068.1 + 3.1.2 + $(MicrosoftAspNetCoreComponentsPackageVersion) + $(MicrosoftAspNetCoreComponentsPackageVersion) + $(MicrosoftAspNetCoreComponentsPackageVersion) + $(MicrosoftAspNetCoreComponentsPackageVersion) https://dotnetcli.blob.core.windows.net/dotnet/ + https://dotnetclimsrc.blob.core.windows.net/dotnet/ - + \ No newline at end of file diff --git a/global.json b/global.json index 88df91565f..324a0158be 100644 --- a/global.json +++ b/global.json @@ -1,9 +1,9 @@ { "sdk": { - "version": "3.1.100" + "version": "3.1.102-servicing-014873" }, "tools": { - "dotnet": "3.1.100", + "dotnet": "3.1.102-servicing-014873", "runtimes": { "dotnet/x64": [ "$(MicrosoftNETCoreAppInternalPackageVersion)" diff --git a/src/Components/Analyzers/src/ComponentFacts.cs b/src/Components/Analyzers/src/ComponentFacts.cs deleted file mode 100644 index 75403ce282..0000000000 --- a/src/Components/Analyzers/src/ComponentFacts.cs +++ /dev/null @@ -1,111 +0,0 @@ -// 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.Linq; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; - -namespace Microsoft.AspNetCore.Components.Analyzers -{ - internal static class ComponentFacts - { - public static bool IsAnyParameter(ComponentSymbols symbols, IPropertySymbol property) - { - if (symbols == null) - { - throw new ArgumentNullException(nameof(symbols)); - } - - if (property == null) - { - throw new ArgumentNullException(nameof(property)); - } - - return property.GetAttributes().Any(a => - { - return a.AttributeClass == symbols.ParameterAttribute || a.AttributeClass == symbols.CascadingParameterAttribute; - }); - } - - public static bool IsParameter(ComponentSymbols symbols, IPropertySymbol property) - { - if (symbols == null) - { - throw new ArgumentNullException(nameof(symbols)); - } - - if (property == null) - { - throw new ArgumentNullException(nameof(property)); - } - - return property.GetAttributes().Any(a => a.AttributeClass == symbols.ParameterAttribute); - } - - public static bool IsParameterWithCaptureUnmatchedValues(ComponentSymbols symbols, IPropertySymbol property) - { - if (symbols == null) - { - throw new ArgumentNullException(nameof(symbols)); - } - - if (property == null) - { - throw new ArgumentNullException(nameof(property)); - } - - var attribute = property.GetAttributes().FirstOrDefault(a => a.AttributeClass == symbols.ParameterAttribute); - if (attribute == null) - { - return false; - } - - foreach (var kvp in attribute.NamedArguments) - { - if (string.Equals(kvp.Key, ComponentsApi.ParameterAttribute.CaptureUnmatchedValues, StringComparison.Ordinal)) - { - return kvp.Value.Value as bool? ?? false; - } - } - - return false; - } - - public static bool IsCascadingParameter(ComponentSymbols symbols, IPropertySymbol property) - { - if (symbols == null) - { - throw new ArgumentNullException(nameof(symbols)); - } - - if (property == null) - { - throw new ArgumentNullException(nameof(property)); - } - - return property.GetAttributes().Any(a => a.AttributeClass == symbols.CascadingParameterAttribute); - } - - public static bool IsComponent(ComponentSymbols symbols, Compilation compilation, INamedTypeSymbol type) - { - if (symbols is null) - { - throw new ArgumentNullException(nameof(symbols)); - } - - if (type is null) - { - throw new ArgumentNullException(nameof(type)); - } - - var conversion = compilation.ClassifyConversion(symbols.IComponentType, type); - if (!conversion.Exists || !conversion.IsExplicit) - { - return false; - } - - return true; - } - } -} diff --git a/src/Components/Analyzers/src/ComponentInternalUsageDiagnosticAnalzyer.cs b/src/Components/Analyzers/src/ComponentInternalUsageDiagnosticAnalzyer.cs deleted file mode 100644 index 8f6272c326..0000000000 --- a/src/Components/Analyzers/src/ComponentInternalUsageDiagnosticAnalzyer.cs +++ /dev/null @@ -1,43 +0,0 @@ -// 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.Collections.Immutable; -using Microsoft.AspNetCore.Components.Analyzers; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Diagnostics; - -namespace Microsoft.Extensions.Internal -{ - /// - /// This API supports infrastructure and is not intended to be used - /// directly from your code. This API may change or be removed in future releases. - /// - [DiagnosticAnalyzer(LanguageNames.CSharp)] - public class ComponentInternalUsageDiagnosticAnalyzer : DiagnosticAnalyzer - { - private readonly InternalUsageAnalyzer _inner; - - public ComponentInternalUsageDiagnosticAnalyzer() - { - // We don't have in *internal* attribute in Blazor. - _inner = new InternalUsageAnalyzer(IsInInternalNamespace, hasInternalAttribute: null, DiagnosticDescriptors.DoNotUseRenderTreeTypes); - } - - public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(DiagnosticDescriptors.DoNotUseRenderTreeTypes); - - public override void Initialize(AnalysisContext context) - { - _inner.Register(context); - } - - private static bool IsInInternalNamespace(ISymbol symbol) - { - if (symbol?.ContainingNamespace?.ToDisplayString() is string ns) - { - return string.Equals(ns, "Microsoft.AspNetCore.Components.RenderTree"); - } - - return false; - } - } -} diff --git a/src/Components/Analyzers/src/ComponentParameterAnalyzer.cs b/src/Components/Analyzers/src/ComponentParameterAnalyzer.cs deleted file mode 100644 index c6d8670dcb..0000000000 --- a/src/Components/Analyzers/src/ComponentParameterAnalyzer.cs +++ /dev/null @@ -1,125 +0,0 @@ -// 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.Collections.Generic; -using System.Collections.Immutable; -using System.Linq; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.Diagnostics; - -namespace Microsoft.AspNetCore.Components.Analyzers -{ - [DiagnosticAnalyzer(LanguageNames.CSharp)] - public class ComponentParameterAnalyzer : DiagnosticAnalyzer - { - public ComponentParameterAnalyzer() - { - SupportedDiagnostics = ImmutableArray.Create(new[] - { - DiagnosticDescriptors.ComponentParametersShouldBePublic, - DiagnosticDescriptors.ComponentParameterSettersShouldBePublic, - DiagnosticDescriptors.ComponentParameterCaptureUnmatchedValuesMustBeUnique, - DiagnosticDescriptors.ComponentParameterCaptureUnmatchedValuesHasWrongType, - }); - } - - public override ImmutableArray SupportedDiagnostics { get; } - - public override void Initialize(AnalysisContext context) - { - context.RegisterCompilationStartAction(context => - { - if (!ComponentSymbols.TryCreate(context.Compilation, out var symbols)) - { - // Types we need are not defined. - return; - } - - // This operates per-type because one of the validations we need has to look for duplicates - // defined on the same type. - context.RegisterSymbolStartAction(context => - { - var properties = new List(); - - var type = (INamedTypeSymbol)context.Symbol; - foreach (var member in type.GetMembers()) - { - if (member is IPropertySymbol property && ComponentFacts.IsParameter(symbols, property)) - { - // Annotated with [Parameter]. We ignore [CascadingParameter]'s because they don't interact with tooling and don't currently have any analyzer restrictions. - properties.Add(property); - } - } - - if (properties.Count == 0) - { - return; - } - - context.RegisterSymbolEndAction(context => - { - var captureUnmatchedValuesParameters = new List(); - - // Per-property validations - foreach (var property in properties) - { - var propertyLocation = property.Locations.FirstOrDefault(); - if (propertyLocation == null) - { - continue; - } - - if (property.DeclaredAccessibility != Accessibility.Public) - { - context.ReportDiagnostic(Diagnostic.Create( - DiagnosticDescriptors.ComponentParametersShouldBePublic, - propertyLocation, - property.ToDisplayString(SymbolDisplayFormat.CSharpErrorMessageFormat))); - } - else if (property.SetMethod?.DeclaredAccessibility != Accessibility.Public) - { - context.ReportDiagnostic(Diagnostic.Create( - DiagnosticDescriptors.ComponentParameterSettersShouldBePublic, - propertyLocation, - property.ToDisplayString(SymbolDisplayFormat.CSharpErrorMessageFormat))); - } - - if (ComponentFacts.IsParameterWithCaptureUnmatchedValues(symbols, property)) - { - captureUnmatchedValuesParameters.Add(property); - - // Check the type, we need to be able to assign a Dictionary - var conversion = context.Compilation.ClassifyConversion(symbols.ParameterCaptureUnmatchedValuesRuntimeType, property.Type); - if (!conversion.Exists || conversion.IsExplicit) - { - context.ReportDiagnostic(Diagnostic.Create( - DiagnosticDescriptors.ComponentParameterCaptureUnmatchedValuesHasWrongType, - propertyLocation, - property.ToDisplayString(SymbolDisplayFormat.CSharpErrorMessageFormat), - property.Type.ToDisplayString(SymbolDisplayFormat.CSharpErrorMessageFormat), - symbols.ParameterCaptureUnmatchedValuesRuntimeType.ToDisplayString(SymbolDisplayFormat.CSharpErrorMessageFormat))); - } - } - } - - // Check if the type defines multiple CaptureUnmatchedValues parameters. Doing this outside the loop means we place the - // errors on the type. - if (captureUnmatchedValuesParameters.Count > 1) - { - context.ReportDiagnostic(Diagnostic.Create( - DiagnosticDescriptors.ComponentParameterCaptureUnmatchedValuesMustBeUnique, - context.Symbol.Locations[0], - type.ToDisplayString(SymbolDisplayFormat.CSharpErrorMessageFormat), - Environment.NewLine, - string.Join( - Environment.NewLine, - captureUnmatchedValuesParameters.Select(p => p.ToDisplayString(SymbolDisplayFormat.CSharpErrorMessageFormat)).OrderBy(n => n)))); - } - }); - }, SymbolKind.NamedType); - }); - } - } -} diff --git a/src/Components/Analyzers/src/ComponentParameterUsageAnalyzer.cs b/src/Components/Analyzers/src/ComponentParameterUsageAnalyzer.cs deleted file mode 100644 index 8df3167b83..0000000000 --- a/src/Components/Analyzers/src/ComponentParameterUsageAnalyzer.cs +++ /dev/null @@ -1,114 +0,0 @@ -// 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.Collections.Immutable; -using System.Linq; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Operations; - -namespace Microsoft.AspNetCore.Components.Analyzers -{ - [DiagnosticAnalyzer(LanguageNames.CSharp)] - public class ComponentParameterUsageAnalyzer : DiagnosticAnalyzer - { - public ComponentParameterUsageAnalyzer() - { - SupportedDiagnostics = ImmutableArray.Create(new[] - { - DiagnosticDescriptors.ComponentParametersShouldNotBeSetOutsideOfTheirDeclaredComponent, - }); - } - - public override ImmutableArray SupportedDiagnostics { get; } - - public override void Initialize(AnalysisContext context) - { - context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics); - context.RegisterCompilationStartAction(context => - { - if (!ComponentSymbols.TryCreate(context.Compilation, out var symbols)) - { - // Types we need are not defined. - return; - } - - context.RegisterOperationBlockStartAction(startBlockContext => - { - startBlockContext.RegisterOperationAction(context => - { - IOperation leftHandSide; - - if (context.Operation is IAssignmentOperation assignmentOperation) - { - leftHandSide = assignmentOperation.Target; - } - else - { - var incrementOrDecrementOperation = (IIncrementOrDecrementOperation)context.Operation; - leftHandSide = incrementOrDecrementOperation.Target; - } - - if (leftHandSide == null) - { - // Malformed assignment, no left hand side. - return; - } - - if (leftHandSide.Kind != OperationKind.PropertyReference) - { - // We don't want to capture situations where a user does - // MyOtherProperty = aComponent.SomeParameter - return; - } - - var propertyReference = (IPropertyReferenceOperation)leftHandSide; - var componentProperty = (IPropertySymbol)propertyReference.Member; - - if (!ComponentFacts.IsParameter(symbols, componentProperty)) - { - // This is not a property reference that we care about, it is not decorated with [Parameter]. - return; - } - - var propertyContainingType = componentProperty.ContainingType; - if (!ComponentFacts.IsComponent(symbols, context.Compilation, propertyContainingType)) - { - // Someone referenced a property as [Parameter] inside something that is not a component. - return; - } - - var assignmentContainingType = startBlockContext.OwningSymbol?.ContainingType; - if (assignmentContainingType == null) - { - // Assignment location has no containing type. Most likely we're operating on malformed code, don't try and validate. - return; - } - - var conversion = context.Compilation.ClassifyConversion(propertyContainingType, assignmentContainingType); - if (conversion.Exists && conversion.IsIdentity) - { - // The assignment is taking place inside of the declaring component. - return; - } - - if (conversion.Exists && conversion.IsExplicit) - { - // The assignment is taking place within the components type hierarchy. This means the user is setting this in a supported - // scenario. - return; - } - - // At this point the user is referencing a component parameter outside of its declaring class. - - context.ReportDiagnostic(Diagnostic.Create( - DiagnosticDescriptors.ComponentParametersShouldNotBeSetOutsideOfTheirDeclaredComponent, - propertyReference.Syntax.GetLocation(), - propertyReference.Member.Name)); - }, OperationKind.SimpleAssignment, OperationKind.CompoundAssignment, OperationKind.CoalesceAssignment, OperationKind.Increment, OperationKind.Decrement); - }); - }); - } - } -} diff --git a/src/Components/Analyzers/src/ComponentParametersShouldBePublicCodeFixProvider.cs b/src/Components/Analyzers/src/ComponentParametersShouldBePublicCodeFixProvider.cs deleted file mode 100644 index 173633f0e9..0000000000 --- a/src/Components/Analyzers/src/ComponentParametersShouldBePublicCodeFixProvider.cs +++ /dev/null @@ -1,88 +0,0 @@ -// 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.Collections.Immutable; -using System.Composition; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CodeActions; -using Microsoft.CodeAnalysis.CodeFixes; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; - -namespace Microsoft.AspNetCore.Components.Analyzers -{ - [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(ComponentParametersShouldBePublicCodeFixProvider)), Shared] - public class ComponentParametersShouldBePublicCodeFixProvider : CodeFixProvider - { - private static readonly LocalizableString Title = new LocalizableResourceString(nameof(Resources.ComponentParametersShouldBePublic_FixTitle), Resources.ResourceManager, typeof(Resources)); - - public override ImmutableArray FixableDiagnosticIds - => ImmutableArray.Create(DiagnosticDescriptors.ComponentParametersShouldBePublic.Id); - - public sealed override FixAllProvider GetFixAllProvider() - { - // See https://github.com/dotnet/roslyn/blob/master/docs/analyzers/FixAllProvider.md for more information on Fix All Providers - return WellKnownFixAllProviders.BatchFixer; - } - - public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) - { - var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); - var diagnostic = context.Diagnostics.First(); - var diagnosticSpan = diagnostic.Location.SourceSpan; - - // Find the type declaration identified by the diagnostic. - var declaration = root.FindToken(diagnosticSpan.Start).Parent.AncestorsAndSelf().OfType().First(); - - // Register a code action that will invoke the fix. - var title = Title.ToString(); - context.RegisterCodeFix( - CodeAction.Create( - title: title, - createChangedDocument: c => GetTransformedDocumentAsync(context.Document, root, declaration), - equivalenceKey: title), - diagnostic); - } - - private Task GetTransformedDocumentAsync( - Document document, - SyntaxNode root, - PropertyDeclarationSyntax declarationNode) - { - var updatedDeclarationNode = HandlePropertyDeclaration(declarationNode); - var newSyntaxRoot = root.ReplaceNode(declarationNode, updatedDeclarationNode); - return Task.FromResult(document.WithSyntaxRoot(newSyntaxRoot)); - } - - private SyntaxNode HandlePropertyDeclaration(PropertyDeclarationSyntax node) - { - TypeSyntax type = node.Type; - if (type == null || type.IsMissing) - { - return null; - } - - var newModifiers = node.Modifiers; - for (var i = 0; i < node.Modifiers.Count; i++) - { - var modifier = node.Modifiers[i]; - if (modifier.IsKind(SyntaxKind.PrivateKeyword) || - modifier.IsKind(SyntaxKind.ProtectedKeyword) || - modifier.IsKind(SyntaxKind.InternalKeyword) || - - // We also remove public in case the user has written something totally backwards such as private public protected Foo - modifier.IsKind(SyntaxKind.PublicKeyword)) - { - newModifiers = newModifiers.Remove(modifier); - } - } - - var publicModifier = SyntaxFactory.Token(SyntaxKind.PublicKeyword); - newModifiers = newModifiers.Insert(0, publicModifier); - node = node.WithModifiers(newModifiers); - return node; - } - } -} diff --git a/src/Components/Analyzers/src/ComponentSymbols.cs b/src/Components/Analyzers/src/ComponentSymbols.cs deleted file mode 100644 index d115e27f53..0000000000 --- a/src/Components/Analyzers/src/ComponentSymbols.cs +++ /dev/null @@ -1,79 +0,0 @@ -// 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 Microsoft.CodeAnalysis; - -namespace Microsoft.AspNetCore.Components.Analyzers -{ - internal class ComponentSymbols - { - public static bool TryCreate(Compilation compilation, out ComponentSymbols symbols) - { - if (compilation == null) - { - throw new ArgumentNullException(nameof(compilation)); - } - - var parameterAttribute = compilation.GetTypeByMetadataName(ComponentsApi.ParameterAttribute.MetadataName); - if (parameterAttribute == null) - { - symbols = null; - return false; - } - - var cascadingParameterAttribute = compilation.GetTypeByMetadataName(ComponentsApi.CascadingParameterAttribute.MetadataName); - if (cascadingParameterAttribute == null) - { - symbols = null; - return false; - } - - var icomponentType = compilation.GetTypeByMetadataName(ComponentsApi.IComponent.MetadataName); - if (icomponentType == null) - { - symbols = null; - return false; - } - - var dictionary = compilation.GetTypeByMetadataName("System.Collections.Generic.Dictionary`2"); - var @string = compilation.GetSpecialType(SpecialType.System_String); - var @object = compilation.GetSpecialType(SpecialType.System_Object); - if (dictionary == null || @string == null || @object == null) - { - symbols = null; - return false; - } - - var parameterCaptureUnmatchedValuesRuntimeType = dictionary.Construct(@string, @object); - - symbols = new ComponentSymbols( - parameterAttribute, - cascadingParameterAttribute, - parameterCaptureUnmatchedValuesRuntimeType, - icomponentType); - return true; - } - - private ComponentSymbols( - INamedTypeSymbol parameterAttribute, - INamedTypeSymbol cascadingParameterAttribute, - INamedTypeSymbol parameterCaptureUnmatchedValuesRuntimeType, - INamedTypeSymbol icomponentType) - { - ParameterAttribute = parameterAttribute; - CascadingParameterAttribute = cascadingParameterAttribute; - ParameterCaptureUnmatchedValuesRuntimeType = parameterCaptureUnmatchedValuesRuntimeType; - IComponentType = icomponentType; - } - - public INamedTypeSymbol ParameterAttribute { get; } - - // Dictionary - public INamedTypeSymbol ParameterCaptureUnmatchedValuesRuntimeType { get; } - - public INamedTypeSymbol CascadingParameterAttribute { get; } - - public INamedTypeSymbol IComponentType { get; } - } -} diff --git a/src/Components/Analyzers/src/ComponentsApi.cs b/src/Components/Analyzers/src/ComponentsApi.cs deleted file mode 100644 index 73ceff39fd..0000000000 --- a/src/Components/Analyzers/src/ComponentsApi.cs +++ /dev/null @@ -1,32 +0,0 @@ -// 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. - -namespace Microsoft.AspNetCore.Components.Analyzers -{ - // Constants for type and method names used in code-generation - // Keep these in sync with the actual definitions - internal static class ComponentsApi - { - public static readonly string AssemblyName = "Microsoft.AspNetCore.Components"; - - public static class ParameterAttribute - { - public static readonly string FullTypeName = "Microsoft.AspNetCore.Components.ParameterAttribute"; - public static readonly string MetadataName = FullTypeName; - - public static readonly string CaptureUnmatchedValues = "CaptureUnmatchedValues"; - } - - public static class CascadingParameterAttribute - { - public static readonly string FullTypeName = "Microsoft.AspNetCore.Components.CascadingParameterAttribute"; - public static readonly string MetadataName = FullTypeName; - } - - public static class IComponent - { - public static readonly string FullTypeName = "Microsoft.AspNetCore.Components.IComponent"; - public static readonly string MetadataName = FullTypeName; - } - } -} diff --git a/src/Components/Analyzers/src/DiagnosticDescriptors.cs b/src/Components/Analyzers/src/DiagnosticDescriptors.cs deleted file mode 100644 index 8eb86b3212..0000000000 --- a/src/Components/Analyzers/src/DiagnosticDescriptors.cs +++ /dev/null @@ -1,68 +0,0 @@ -// 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.CodeAnalysis; - -namespace Microsoft.AspNetCore.Components.Analyzers -{ - internal static class DiagnosticDescriptors - { - // Note: The Razor Compiler (including Components features) use the RZ prefix for diagnostics, so there's currently - // no change of clashing between that and the BL prefix used here. - // - // Tracking https://github.com/aspnet/AspNetCore/issues/10382 to rationalize this - public static readonly DiagnosticDescriptor ComponentParameterSettersShouldBePublic = new DiagnosticDescriptor( - "BL0001", - new LocalizableResourceString(nameof(Resources.ComponentParameterSettersShouldBePublic_Title), Resources.ResourceManager, typeof(Resources)), - new LocalizableResourceString(nameof(Resources.ComponentParameterSettersShouldBePublic_Format), Resources.ResourceManager, typeof(Resources)), - "Encapsulation", - DiagnosticSeverity.Error, - isEnabledByDefault: true, - description: new LocalizableResourceString(nameof(Resources.ComponentParameterSettersShouldBePublic_Description), Resources.ResourceManager, typeof(Resources))); - - public static readonly DiagnosticDescriptor ComponentParameterCaptureUnmatchedValuesMustBeUnique = new DiagnosticDescriptor( - "BL0002", - new LocalizableResourceString(nameof(Resources.ComponentParameterCaptureUnmatchedValuesMustBeUnique_Title), Resources.ResourceManager, typeof(Resources)), - new LocalizableResourceString(nameof(Resources.ComponentParameterCaptureUnmatchedValuesMustBeUnique_Format), Resources.ResourceManager, typeof(Resources)), - "Usage", - DiagnosticSeverity.Warning, - isEnabledByDefault: true, - description: new LocalizableResourceString(nameof(Resources.ComponentParameterCaptureUnmatchedValuesMustBeUnique_Description), Resources.ResourceManager, typeof(Resources))); - - public static readonly DiagnosticDescriptor ComponentParameterCaptureUnmatchedValuesHasWrongType = new DiagnosticDescriptor( - "BL0003", - new LocalizableResourceString(nameof(Resources.ComponentParameterCaptureUnmatchedValuesHasWrongType_Title), Resources.ResourceManager, typeof(Resources)), - new LocalizableResourceString(nameof(Resources.ComponentParameterCaptureUnmatchedValuesHasWrongType_Format), Resources.ResourceManager, typeof(Resources)), - "Usage", - DiagnosticSeverity.Warning, - isEnabledByDefault: true, - description: new LocalizableResourceString(nameof(Resources.ComponentParameterCaptureUnmatchedValuesHasWrongType_Description), Resources.ResourceManager, typeof(Resources))); - - public static readonly DiagnosticDescriptor ComponentParametersShouldBePublic = new DiagnosticDescriptor( - "BL0004", - new LocalizableResourceString(nameof(Resources.ComponentParameterShouldBePublic_Title), Resources.ResourceManager, typeof(Resources)), - new LocalizableResourceString(nameof(Resources.ComponentParameterShouldBePublic_Format), Resources.ResourceManager, typeof(Resources)), - "Encapsulation", - DiagnosticSeverity.Error, - isEnabledByDefault: true, - description: new LocalizableResourceString(nameof(Resources.ComponentParametersShouldBePublic_Description), Resources.ResourceManager, typeof(Resources))); - - public static readonly DiagnosticDescriptor ComponentParametersShouldNotBeSetOutsideOfTheirDeclaredComponent = new DiagnosticDescriptor( - "BL0005", - new LocalizableResourceString(nameof(Resources.ComponentParameterShouldNotBeSetOutsideOfTheirDeclaredComponent_Title), Resources.ResourceManager, typeof(Resources)), - new LocalizableResourceString(nameof(Resources.ComponentParameterShouldNotBeSetOutsideOfTheirDeclaredComponent_Format), Resources.ResourceManager, typeof(Resources)), - "Usage", - DiagnosticSeverity.Warning, - isEnabledByDefault: true, - description: new LocalizableResourceString(nameof(Resources.ComponentParameterShouldNotBeSetOutsideOfTheirDeclaredComponent_Description), Resources.ResourceManager, typeof(Resources))); - - public static readonly DiagnosticDescriptor DoNotUseRenderTreeTypes = new DiagnosticDescriptor( - "BL0006", - new LocalizableResourceString(nameof(Resources.DoNotUseRenderTreeTypes_Title), Resources.ResourceManager, typeof(Resources)), - new LocalizableResourceString(nameof(Resources.DoNotUseRenderTreeTypes_Description), Resources.ResourceManager, typeof(Resources)), - "Usage", - DiagnosticSeverity.Warning, - isEnabledByDefault: true, - description: new LocalizableResourceString(nameof(Resources.DoNotUseRenderTreeTypes_Description), Resources.ResourceManager, typeof(Resources))); - } -} diff --git a/src/Components/Analyzers/src/InternalUsageAnalyzer.cs b/src/Components/Analyzers/src/InternalUsageAnalyzer.cs deleted file mode 100644 index 92b07a7ab2..0000000000 --- a/src/Components/Analyzers/src/InternalUsageAnalyzer.cs +++ /dev/null @@ -1,126 +0,0 @@ -// 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 Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Diagnostics; - -namespace Microsoft.Extensions.Internal -{ - internal class InternalUsageAnalyzer - { - private readonly Func _isInternalNamespace; - private readonly Func _hasInternalAttribute; - private readonly DiagnosticDescriptor _descriptor; - - /// - /// Creates a new instance of . The creator should provide delegates to help determine whether - /// a given symbol is internal or not, and a to create errors. - /// - /// The delegate used to check if a symbol belongs to an internal namespace. - /// The delegate used to check if a symbol has an internal attribute. - /// - /// The used to create errors. The error message should expect a single parameter - /// used for the display name of the member. - /// - public InternalUsageAnalyzer(Func isInInternalNamespace, Func hasInternalAttribute, DiagnosticDescriptor descriptor) - { - _isInternalNamespace = isInInternalNamespace ?? new Func((_) => false); - _hasInternalAttribute = hasInternalAttribute ?? new Func((_) => false); - _descriptor = descriptor ?? throw new ArgumentNullException(nameof(descriptor)); - } - - public void Register(AnalysisContext context) - { - context.EnableConcurrentExecution(); - context.RegisterSyntaxNodeAction(AnalyzeNode, - SyntaxKind.SimpleMemberAccessExpression, - SyntaxKind.ObjectCreationExpression, - SyntaxKind.ClassDeclaration, - SyntaxKind.Parameter); - } - - private void AnalyzeNode(SyntaxNodeAnalysisContext context) - { - switch (context.Node) - { - case MemberAccessExpressionSyntax memberAccessSyntax: - { - if (context.SemanticModel.GetSymbolInfo(context.Node, context.CancellationToken).Symbol is ISymbol symbol && - symbol.ContainingAssembly != context.Compilation.Assembly) - { - var containingType = symbol.ContainingType; - - if (HasInternalAttribute(symbol)) - { - context.ReportDiagnostic(Diagnostic.Create(_descriptor, memberAccessSyntax.Name.GetLocation(), $"{containingType}.{symbol.Name}")); - return; - } - - if (IsInInternalNamespace(containingType) || HasInternalAttribute(containingType)) - { - context.ReportDiagnostic(Diagnostic.Create(_descriptor, memberAccessSyntax.Name.GetLocation(), containingType)); - return; - } - } - return; - } - - case ObjectCreationExpressionSyntax creationSyntax: - { - if (context.SemanticModel.GetSymbolInfo(context.Node, context.CancellationToken).Symbol is ISymbol symbol && - symbol.ContainingAssembly != context.Compilation.Assembly) - { - var containingType = symbol.ContainingType; - - if (HasInternalAttribute(symbol)) - { - context.ReportDiagnostic(Diagnostic.Create(_descriptor, creationSyntax.GetLocation(), containingType)); - return; - } - - if (IsInInternalNamespace(containingType) || HasInternalAttribute(containingType)) - { - context.ReportDiagnostic(Diagnostic.Create(_descriptor, creationSyntax.Type.GetLocation(), containingType)); - return; - } - } - - return; - } - - case ClassDeclarationSyntax declarationSyntax: - { - if (context.SemanticModel.GetDeclaredSymbol(declarationSyntax)?.BaseType is ISymbol symbol && - symbol.ContainingAssembly != context.Compilation.Assembly && - (IsInInternalNamespace(symbol) || HasInternalAttribute(symbol)) && - declarationSyntax.BaseList?.Types.Count > 0) - { - context.ReportDiagnostic(Diagnostic.Create(_descriptor, declarationSyntax.BaseList.Types[0].GetLocation(), symbol)); - } - - return; - } - - case ParameterSyntax parameterSyntax: - { - if (context.SemanticModel.GetDeclaredSymbol(parameterSyntax)?.Type is ISymbol symbol && - symbol.ContainingAssembly != context.Compilation.Assembly && - (IsInInternalNamespace(symbol) || HasInternalAttribute(symbol))) - { - - context.ReportDiagnostic(Diagnostic.Create(_descriptor, parameterSyntax.GetLocation(), symbol)); - } - - return; - } - } - } - - private bool HasInternalAttribute(ISymbol symbol) => _hasInternalAttribute(symbol); - - private bool IsInInternalNamespace(ISymbol symbol) => _isInternalNamespace(symbol); - } -} diff --git a/src/Components/Analyzers/src/Microsoft.AspNetCore.Components.Analyzers.csproj b/src/Components/Analyzers/src/Microsoft.AspNetCore.Components.Analyzers.csproj deleted file mode 100644 index a83904f245..0000000000 --- a/src/Components/Analyzers/src/Microsoft.AspNetCore.Components.Analyzers.csproj +++ /dev/null @@ -1,23 +0,0 @@ - - - - netstandard2.0 - false - true - false - Roslyn analyzers for ASP.NET Core Components. - true - false - - - - - - - - - - - - - diff --git a/src/Components/Analyzers/src/Properties/AssemblyInfo.cs b/src/Components/Analyzers/src/Properties/AssemblyInfo.cs deleted file mode 100644 index 6e6689b592..0000000000 --- a/src/Components/Analyzers/src/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,3 +0,0 @@ -using System.Runtime.CompilerServices; - -[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Components.Analyzers.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] diff --git a/src/Components/Analyzers/src/Resources.resx b/src/Components/Analyzers/src/Resources.resx deleted file mode 100644 index ed4f36c531..0000000000 --- a/src/Components/Analyzers/src/Resources.resx +++ /dev/null @@ -1,177 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Component parameters should have public setters. - - - Component parameter '{0}' should have a public setter. - - - Component parameter should have public setters. - - - Components may only define a single parameter with CaptureUnmatchedValues. - - - Component type '{0}' defines properties multiple parameters with CaptureUnmatchedValues. Properties: {1}{2} - - - Component has multiple CaptureUnmatchedValues parameters - - - Component parameters with CaptureUnmatchedValues must be a correct type. - - - Component parameter '{0}' defines CaptureUnmatchedValues but has an unsupported type '{1}'. Use a type assignable from '{2}'. - - - Component parameter with CaptureUnmatchedValues has the wrong type - - - Component parameter '{0}' should be public. - - - Component parameter should be public. - - - Component parameters should be public. - - - Make component parameters public. - - - Component parameters should not be set outside of their declared component. Doing so may result in unexpected behavior at runtime. - - - Component parameter '{0}' should not be set outside of its component. - - - Component parameter should not be set outside of its component. - - - The types in 'Microsoft.AspNetCore.Components.RenderTree' are not recommended for use outside of the Blazor framework. These type definitions will change in future releases. - - - The type or member {0} is is not recommended for use outside of the Blazor frameworks. Types defined in 'Microsoft.AspNetCore.Components.RenderTree' will change in future releases. - - - Do not use RenderTree types - - \ No newline at end of file diff --git a/src/Components/Analyzers/src/build/netstandard2.0/Microsoft.AspNetCore.Components.Analyzers.props b/src/Components/Analyzers/src/build/netstandard2.0/Microsoft.AspNetCore.Components.Analyzers.props deleted file mode 100644 index 0ba7b4da05..0000000000 --- a/src/Components/Analyzers/src/build/netstandard2.0/Microsoft.AspNetCore.Components.Analyzers.props +++ /dev/null @@ -1,5 +0,0 @@ - - - true - - diff --git a/src/Components/Analyzers/test/AnalyzerTestBase.cs b/src/Components/Analyzers/test/AnalyzerTestBase.cs deleted file mode 100644 index 8c1ae95376..0000000000 --- a/src/Components/Analyzers/test/AnalyzerTestBase.cs +++ /dev/null @@ -1,67 +0,0 @@ -// 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.IO; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Analyzer.Testing; -using Microsoft.AspNetCore.Testing; -using Microsoft.CodeAnalysis; - -namespace Microsoft.AspNetCore.Components.Analyzers -{ - public abstract class AnalyzerTestBase - { - private static readonly string ProjectDirectory = GetProjectDirectory(); - - public TestSource Read(string source) - { - if (!source.EndsWith(".cs")) - { - source = source + ".cs"; - } - - var filePath = Path.Combine(ProjectDirectory, "TestFiles", GetType().Name, source); - if (!File.Exists(filePath)) - { - throw new FileNotFoundException($"TestFile {source} could not be found at {filePath}.", filePath); - } - - var fileContent = File.ReadAllText(filePath); - return TestSource.Read(fileContent); - } - - public Project CreateProject(string source) - { - if (!source.EndsWith(".cs")) - { - source = source + ".cs"; - } - - var read = Read(source); - return DiagnosticProject.Create(GetType().Assembly, new[] { read.Source, }); - } - - public Task CreateCompilationAsync(string source) - { - return CreateProject(source).GetCompilationAsync(); - } - - private static string GetProjectDirectory() - { - // On helix we use the published test files - if (SkipOnHelixAttribute.OnHelix()) - { - return AppContext.BaseDirectory; - } - - // This test code needs to be updated to support distributed testing. - // See https://github.com/aspnet/AspNetCore/issues/10422 -#pragma warning disable 0618 - var solutionDirectory = TestPathUtilities.GetSolutionRootDirectory("Components"); -#pragma warning restore 0618 - var projectDirectory = Path.Combine(solutionDirectory, "Analyzers", "test"); - return projectDirectory; - } - } -} diff --git a/src/Components/Analyzers/test/ComponentAnalyzerDiagnosticAnalyzerRunner.cs b/src/Components/Analyzers/test/ComponentAnalyzerDiagnosticAnalyzerRunner.cs deleted file mode 100644 index 727f060bd4..0000000000 --- a/src/Components/Analyzers/test/ComponentAnalyzerDiagnosticAnalyzerRunner.cs +++ /dev/null @@ -1,31 +0,0 @@ -// 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.Analyzer.Testing; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Diagnostics; - -namespace Microsoft.AspNetCore.Components.Analyzers -{ - internal class ComponentAnalyzerDiagnosticAnalyzerRunner : DiagnosticAnalyzerRunner - { - public ComponentAnalyzerDiagnosticAnalyzerRunner(DiagnosticAnalyzer analyzer) - { - Analyzer = analyzer; - } - - public DiagnosticAnalyzer Analyzer { get; } - - public Task GetDiagnosticsAsync(string source) - { - return GetDiagnosticsAsync(sources: new[] { source }, Analyzer, Array.Empty()); - } - - public Task GetDiagnosticsAsync(Project project) - { - return GetDiagnosticsAsync(new[] { project }, Analyzer, Array.Empty()); - } - } -} diff --git a/src/Components/Analyzers/test/ComponentInternalUsageDiagnoticsAnalyzerTest.cs b/src/Components/Analyzers/test/ComponentInternalUsageDiagnoticsAnalyzerTest.cs deleted file mode 100644 index 92e2252304..0000000000 --- a/src/Components/Analyzers/test/ComponentInternalUsageDiagnoticsAnalyzerTest.cs +++ /dev/null @@ -1,60 +0,0 @@ -// 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.Threading.Tasks; -using Microsoft.AspNetCore.Analyzer.Testing; -using Microsoft.Extensions.Internal; -using Xunit; - -namespace Microsoft.AspNetCore.Components.Analyzers -{ - public class ComponentInternalUsageDiagnoticsAnalyzerTest : AnalyzerTestBase - { - public ComponentInternalUsageDiagnoticsAnalyzerTest() - { - Analyzer = new ComponentInternalUsageDiagnosticAnalyzer(); - Runner = new ComponentAnalyzerDiagnosticAnalyzerRunner(Analyzer); - } - - private ComponentInternalUsageDiagnosticAnalyzer Analyzer { get; } - private ComponentAnalyzerDiagnosticAnalyzerRunner Runner { get; } - - [Fact] - public async Task InternalUsage_FindsUseOfRenderTreeFrameAsParameter() - { - // Arrange - var source = Read("UsesRenderTreeFrameAsParameter"); - - // Act - var diagnostics = await Runner.GetDiagnosticsAsync(source.Source); - - // Assert - Assert.Collection( - diagnostics, - diagnostic => - { - Assert.Same(DiagnosticDescriptors.DoNotUseRenderTreeTypes, diagnostic.Descriptor); - AnalyzerAssert.DiagnosticLocation(source.DefaultMarkerLocation, diagnostic.Location); - }); - } - - [Fact] - public async Task InternalUsage_FindsUseOfRenderTreeType() - { - // Arrange - var source = Read("UsesRenderTreeFrameTypeAsLocal"); - - // Act - var diagnostics = await Runner.GetDiagnosticsAsync(source.Source); - - // Assert - Assert.Collection( - diagnostics, - diagnostic => - { - Assert.Same(DiagnosticDescriptors.DoNotUseRenderTreeTypes, diagnostic.Descriptor); - AnalyzerAssert.DiagnosticLocation(source.DefaultMarkerLocation, diagnostic.Location); - }); - } - } -} diff --git a/src/Components/Analyzers/test/ComponentParameterCaptureUnmatchedValuesHasWrongTypeTest.cs b/src/Components/Analyzers/test/ComponentParameterCaptureUnmatchedValuesHasWrongTypeTest.cs deleted file mode 100644 index e4673c3747..0000000000 --- a/src/Components/Analyzers/test/ComponentParameterCaptureUnmatchedValuesHasWrongTypeTest.cs +++ /dev/null @@ -1,80 +0,0 @@ -// 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.CodeAnalysis; -using Microsoft.CodeAnalysis.Diagnostics; -using TestHelper; -using Xunit; - -namespace Microsoft.AspNetCore.Components.Analyzers.Test -{ - public class ComponentParameterCaptureUnmatchedValuesHasWrongTypeTest : DiagnosticVerifier - { - [Theory] - [InlineData("System.Collections.Generic.IEnumerable>")] - [InlineData("System.Collections.Generic.Dictionary")] - [InlineData("System.Collections.Generic.IDictionary")] - [InlineData("System.Collections.Generic.IReadOnlyDictionary")] - public void IgnoresPropertiesWithSupportedType(string propertyType) - { - var test = $@" - namespace ConsoleApplication1 - {{ - using {typeof(ParameterAttribute).Namespace}; - class TypeName - {{ - [Parameter(CaptureUnmatchedValues = true)] public {propertyType} MyProperty {{ get; set; }} - }} - }}" + ComponentsTestDeclarations.Source; - - VerifyCSharpDiagnostic(test); - } - - [Fact] - public void IgnoresPropertiesWithCaptureUnmatchedValuesFalse() - { - var test = $@" - namespace ConsoleApplication1 - {{ - using {typeof(ParameterAttribute).Namespace}; - class TypeName - {{ - [Parameter(CaptureUnmatchedValues = false)] public string MyProperty {{ get; set; }} - }} - }}" + ComponentsTestDeclarations.Source; - - VerifyCSharpDiagnostic(test); - } - - [Fact] - public void AddsDiagnosticForInvalidType() - { - var test = $@" - namespace ConsoleApplication1 - {{ - using {typeof(ParameterAttribute).Namespace}; - class TypeName - {{ - [Parameter(CaptureUnmatchedValues = true)] public string MyProperty {{ get; set; }} - }} - }}" + ComponentsTestDeclarations.Source; - - VerifyCSharpDiagnostic(test, - new DiagnosticResult - { - Id = DiagnosticDescriptors.ComponentParameterCaptureUnmatchedValuesHasWrongType.Id, - Message = "Component parameter 'ConsoleApplication1.TypeName.MyProperty' defines CaptureUnmatchedValues but has an unsupported type 'string'. Use a type assignable from 'System.Collections.Generic.Dictionary'.", - Severity = DiagnosticSeverity.Warning, - Locations = new[] - { - new DiagnosticResultLocation("Test0.cs", 7, 70) - } - }); - } - - protected override DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer() - { - return new ComponentParameterAnalyzer(); - } - } -} diff --git a/src/Components/Analyzers/test/ComponentParameterCaptureUnmatchedValuesMustBeUniqueTest.cs b/src/Components/Analyzers/test/ComponentParameterCaptureUnmatchedValuesMustBeUniqueTest.cs deleted file mode 100644 index f7b055caa7..0000000000 --- a/src/Components/Analyzers/test/ComponentParameterCaptureUnmatchedValuesMustBeUniqueTest.cs +++ /dev/null @@ -1,69 +0,0 @@ -// 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 Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Diagnostics; -using TestHelper; -using Xunit; - -namespace Microsoft.AspNetCore.Components.Analyzers.Test -{ - public class ComponentParameterCaptureUnmatchedValuesMustBeUniqueTest : DiagnosticVerifier - { - [Fact] - public void IgnoresPropertiesWithCaptureUnmatchedValuesFalse() - { - var test = $@" - namespace ConsoleApplication1 - {{ - using System.Collections.Generic; - using {typeof(ParameterAttribute).Namespace}; - class TypeName - {{ - [Parameter(CaptureUnmatchedValues = false)] public string MyProperty {{ get; set; }} - [Parameter(CaptureUnmatchedValues = true)] public Dictionary MyOtherProperty {{ get; set; }} - }} - }}" + ComponentsTestDeclarations.Source; - - VerifyCSharpDiagnostic(test); - } - - [Fact] - public void AddsDiagnosticForMultipleCaptureUnmatchedValuesProperties() - { - var test = $@" - namespace ConsoleApplication1 - {{ - using System.Collections.Generic; - using {typeof(ParameterAttribute).Namespace}; - class TypeName - {{ - [Parameter(CaptureUnmatchedValues = true)] public Dictionary MyProperty {{ get; set; }} - [Parameter(CaptureUnmatchedValues = true)] public Dictionary MyOtherProperty {{ get; set; }} - }} - }}" + ComponentsTestDeclarations.Source; - - var message = @"Component type 'ConsoleApplication1.TypeName' defines properties multiple parameters with CaptureUnmatchedValues. Properties: " + Environment.NewLine + -"ConsoleApplication1.TypeName.MyOtherProperty" + Environment.NewLine + -"ConsoleApplication1.TypeName.MyProperty"; - - VerifyCSharpDiagnostic(test, - new DiagnosticResult - { - Id = DiagnosticDescriptors.ComponentParameterCaptureUnmatchedValuesMustBeUnique.Id, - Message = message, - Severity = DiagnosticSeverity.Warning, - Locations = new[] - { - new DiagnosticResultLocation("Test0.cs", 6, 15) - } - }); - } - - protected override DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer() - { - return new ComponentParameterAnalyzer(); - } - } -} diff --git a/src/Components/Analyzers/test/ComponentParameterSettersShouldBePublicTest.cs b/src/Components/Analyzers/test/ComponentParameterSettersShouldBePublicTest.cs deleted file mode 100644 index f32bc6048e..0000000000 --- a/src/Components/Analyzers/test/ComponentParameterSettersShouldBePublicTest.cs +++ /dev/null @@ -1,111 +0,0 @@ -// 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.CodeAnalysis; -using Microsoft.CodeAnalysis.Diagnostics; -using TestHelper; -using Xunit; - -namespace Microsoft.AspNetCore.Components.Analyzers -{ - public class ComponentParameterSettersShouldBePublicTest : DiagnosticVerifier - { - [Fact] - public void IgnoresCascadingParameterProperties() - { - var test = $@" - namespace ConsoleApplication1 - {{ - using {typeof(CascadingParameterAttribute).Namespace}; - class TypeName - {{ - [CascadingParameter] string MyProperty {{ get; set; }} - }} - }}" + ComponentsTestDeclarations.Source; - - VerifyCSharpDiagnostic(test); - } - - [Fact] - public void IgnoresPublicSettersProperties() - { - var test = $@" - namespace ConsoleApplication1 - {{ - using {typeof(ParameterAttribute).Namespace}; - class TypeName - {{ - [Parameter] public string MyProperty {{ get; set; }} - }} - }}" + ComponentsTestDeclarations.Source; - - VerifyCSharpDiagnostic(test); - } - - [Fact] - public void IgnoresPrivateSettersNonParameterProperties() - { - var test = $@" - namespace ConsoleApplication1 - {{ - using {typeof(ParameterAttribute).Namespace}; - class TypeName - {{ - private string MyProperty {{ get; private set; }} - }} - }}" + ComponentsTestDeclarations.Source; - - VerifyCSharpDiagnostic(test); - } - - [Fact] - public void ErrorsForNonPublicSetterParameters() - { - var test = $@" - namespace ConsoleApplication1 - {{ - using {typeof(ParameterAttribute).Namespace}; - class TypeName - {{ - [Parameter] public string MyProperty1 {{ get; private set; }} - [Parameter] public string MyProperty2 {{ get; protected set; }} - [Parameter] public string MyProperty3 {{ get; internal set; }} - }} - }}" + ComponentsTestDeclarations.Source; - - VerifyCSharpDiagnostic(test, - new DiagnosticResult - { - Id = DiagnosticDescriptors.ComponentParameterSettersShouldBePublic.Id, - Message = "Component parameter 'ConsoleApplication1.TypeName.MyProperty1' should have a public setter.", - Severity = DiagnosticSeverity.Error, - Locations = new[] - { - new DiagnosticResultLocation("Test0.cs", 7, 39) - } - }, - new DiagnosticResult - { - Id = DiagnosticDescriptors.ComponentParameterSettersShouldBePublic.Id, - Message = "Component parameter 'ConsoleApplication1.TypeName.MyProperty2' should have a public setter.", - Severity = DiagnosticSeverity.Error, - Locations = new[] - { - new DiagnosticResultLocation("Test0.cs", 8, 39) - } - }, - new DiagnosticResult - { - Id = DiagnosticDescriptors.ComponentParameterSettersShouldBePublic.Id, - Message = "Component parameter 'ConsoleApplication1.TypeName.MyProperty3' should have a public setter.", - Severity = DiagnosticSeverity.Error, - Locations = new[] - { - new DiagnosticResultLocation("Test0.cs", 9, 39) - } - }); - } - - protected override DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer() => new ComponentParameterAnalyzer(); - } -} diff --git a/src/Components/Analyzers/test/ComponentParameterUsageAnalyzerTest.cs b/src/Components/Analyzers/test/ComponentParameterUsageAnalyzerTest.cs deleted file mode 100644 index d1c2d2bede..0000000000 --- a/src/Components/Analyzers/test/ComponentParameterUsageAnalyzerTest.cs +++ /dev/null @@ -1,361 +0,0 @@ -// 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.CodeAnalysis; -using Microsoft.CodeAnalysis.Diagnostics; -using TestHelper; -using Xunit; - -namespace Microsoft.AspNetCore.Components.Analyzers -{ - public class ComponentParameterUsageAnalyzerTest : DiagnosticVerifier - { - public ComponentParameterUsageAnalyzerTest() - { - ComponentTestSource = $@" - namespace ConsoleApplication1 - {{ - using {typeof(ParameterAttribute).Namespace}; - class TestComponent : IComponent - {{ - [Parameter] public string TestProperty {{ get; set; }} - [Parameter] public int TestInt {{ get; set; }} - public string NonParameter {{ get; set; }} - }} - }}" + ComponentsTestDeclarations.Source; - } - - private string ComponentTestSource { get; } - - [Fact] - public void ComponentPropertySimpleAssignment_Warns() - { - var test = $@" - namespace ConsoleApplication1 - {{ - using {typeof(ParameterAttribute).Namespace}; - class OtherComponent : IComponent - {{ - private TestComponent _testComponent; - void Render() - {{ - _testComponent = new TestComponent(); - _testComponent.TestProperty = ""Hello World""; - }} - }} - }}" + ComponentTestSource; - - VerifyCSharpDiagnostic(test, - new DiagnosticResult - { - Id = DiagnosticDescriptors.ComponentParametersShouldNotBeSetOutsideOfTheirDeclaredComponent.Id, - Message = "Component parameter 'TestProperty' should not be set outside of its component.", - Severity = DiagnosticSeverity.Warning, - Locations = new[] - { - new DiagnosticResultLocation("Test0.cs", 11, 17) - } - }); - } - - [Fact] - public void ComponentPropertyCoalesceAssignment__Warns() - { - var test = $@" - namespace ConsoleApplication1 - {{ - using {typeof(ParameterAttribute).Namespace}; - class OtherComponent : IComponent - {{ - private TestComponent _testComponent; - void Render() - {{ - _testComponent = new TestComponent(); - _testComponent.TestProperty ??= ""Hello World""; - }} - }} - }}" + ComponentTestSource; - - VerifyCSharpDiagnostic(test, - new DiagnosticResult - { - Id = DiagnosticDescriptors.ComponentParametersShouldNotBeSetOutsideOfTheirDeclaredComponent.Id, - Message = "Component parameter 'TestProperty' should not be set outside of its component.", - Severity = DiagnosticSeverity.Warning, - Locations = new[] - { - new DiagnosticResultLocation("Test0.cs", 11, 17) - } - }); - } - - [Fact] - public void ComponentPropertyCompoundAssignment__Warns() - { - var test = $@" - namespace ConsoleApplication1 - {{ - using {typeof(ParameterAttribute).Namespace}; - class OtherComponent : IComponent - {{ - private TestComponent _testComponent; - void Render() - {{ - _testComponent = new TestComponent(); - _testComponent.TestProperty += ""Hello World""; - }} - }} - }}" + ComponentTestSource; - - VerifyCSharpDiagnostic(test, - new DiagnosticResult - { - Id = DiagnosticDescriptors.ComponentParametersShouldNotBeSetOutsideOfTheirDeclaredComponent.Id, - Message = "Component parameter 'TestProperty' should not be set outside of its component.", - Severity = DiagnosticSeverity.Warning, - Locations = new[] - { - new DiagnosticResultLocation("Test0.cs", 11, 17) - } - }); - } - - [Fact] - public void ComponentPropertyIncrement_Warns() - { - var test = $@" - namespace ConsoleApplication1 - {{ - using {typeof(ParameterAttribute).Namespace}; - class OtherComponent : IComponent - {{ - private TestComponent _testComponent; - void Render() - {{ - _testComponent = new TestComponent(); - _testComponent.TestInt++; - }} - }} - }}" + ComponentTestSource; - - VerifyCSharpDiagnostic(test, - new DiagnosticResult - { - Id = DiagnosticDescriptors.ComponentParametersShouldNotBeSetOutsideOfTheirDeclaredComponent.Id, - Message = "Component parameter 'TestInt' should not be set outside of its component.", - Severity = DiagnosticSeverity.Warning, - Locations = new[] - { - new DiagnosticResultLocation("Test0.cs", 11, 17) - } - }); - } - - [Fact] - public void ComponentPropertyDecrement_Warns() - { - var test = $@" - namespace ConsoleApplication1 - {{ - using {typeof(ParameterAttribute).Namespace}; - class OtherComponent : IComponent - {{ - private TestComponent _testComponent; - void Render() - {{ - _testComponent = new TestComponent(); - _testComponent.TestInt--; - }} - }} - }}" + ComponentTestSource; - - VerifyCSharpDiagnostic(test, - new DiagnosticResult - { - Id = DiagnosticDescriptors.ComponentParametersShouldNotBeSetOutsideOfTheirDeclaredComponent.Id, - Message = "Component parameter 'TestInt' should not be set outside of its component.", - Severity = DiagnosticSeverity.Warning, - Locations = new[] - { - new DiagnosticResultLocation("Test0.cs", 11, 17) - } - }); - } - - [Fact] - public void ComponentPropertyExpression_Ignores() - { - var test = $@" - namespace ConsoleApplication1 - {{ - using {typeof(ParameterAttribute).Namespace}; - class TypeName - {{ - void Method() - {{ - System.IO.Console.WriteLine(new TestComponent().TestProperty); - }} - }} - }}" + ComponentTestSource; - - VerifyCSharpDiagnostic(test); - } - - [Fact] - public void ComponentPropertyExpressionInStatement_Ignores() - { - var test = $@" - namespace ConsoleApplication1 - {{ - using {typeof(ParameterAttribute).Namespace}; - class TypeName - {{ - void Method() - {{ - var testComponent = new TestComponent(); - for (var i = 0; i < testComponent.TestProperty.Length; i++) - {{ - }} - }} - }} - }}" + ComponentTestSource; - - VerifyCSharpDiagnostic(test); - } - - [Fact] - public void RetrievalOfComponentPropertyValueInAssignment_Ignores() - { - var test = $@" - namespace ConsoleApplication1 - {{ - using {typeof(ParameterAttribute).Namespace}; - class TypeName - {{ - void Method() - {{ - var testComponent = new TestComponent(); - AnotherProperty = testComponent.TestProperty; - }} - - public string AnotherProperty {{ get; set; }} - }} - }}" + ComponentTestSource; - - VerifyCSharpDiagnostic(test); - } - - [Fact] - public void ShadowedComponentPropertyAssignment_Ignores() - { - var test = $@" - namespace ConsoleApplication1 - {{ - using {typeof(ParameterAttribute).Namespace}; - class TypeName - {{ - void Method() - {{ - var testComponent = new InheritedComponent(); - testComponent.TestProperty = ""Hello World""; - }} - }} - - class InheritedComponent : TestComponent - {{ - public new string TestProperty {{ get; set; }} - }} - }}" + ComponentTestSource; - - VerifyCSharpDiagnostic(test); - } - - [Fact] - public void InheritedImplicitComponentPropertyAssignment_Ignores() - { - var test = $@" - namespace ConsoleApplication1 - {{ - using {typeof(ParameterAttribute).Namespace}; - class TypeName : TestComponent - {{ - void Method() - {{ - this.TestProperty = ""Hello World""; - }} - }} - }}" + ComponentTestSource; - - VerifyCSharpDiagnostic(test); - } - - [Fact] - public void ImplicitComponentPropertyAssignment_Ignores() - { - var test = $@" - namespace ConsoleApplication1 - {{ - using {typeof(ParameterAttribute).Namespace}; - class TypeName : IComponent - {{ - void Method() - {{ - TestProperty = ""Hello World""; - }} - - [Parameter] public string TestProperty {{ get; set; }} - }} - }}" + ComponentTestSource; - - VerifyCSharpDiagnostic(test); - } - - [Fact] - public void ComponentPropertyAssignment_NonParameter_Ignores() - { - var test = $@" - namespace ConsoleApplication1 - {{ - using {typeof(ParameterAttribute).Namespace}; - class OtherComponent : IComponent - {{ - private TestComponent _testComponent; - void Render() - {{ - _testComponent = new TestComponent(); - _testComponent.NonParameter = ""Hello World""; - }} - }} - }}" + ComponentTestSource; - - VerifyCSharpDiagnostic(test); - } - - [Fact] - public void NonComponentPropertyAssignment_Ignores() - { - var test = $@" - namespace ConsoleApplication1 - {{ - using {typeof(ParameterAttribute).Namespace}; - class OtherComponent : IComponent - {{ - private SomethingElse _testNonComponent; - void Render() - {{ - _testNonComponent = new NotAComponent(); - _testNonComponent.TestProperty = ""Hello World""; - }} - }} - class NotAComponent - {{ - [Parameter] public string TestProperty {{ get; set; }} - }} - }}" + ComponentTestSource; - - VerifyCSharpDiagnostic(test); - } - - protected override DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer() => new ComponentParameterUsageAnalyzer(); - } -} diff --git a/src/Components/Analyzers/test/ComponentParametersShouldBePublicCodeFixProviderTest.cs b/src/Components/Analyzers/test/ComponentParametersShouldBePublicCodeFixProviderTest.cs deleted file mode 100644 index 2e1ee00be0..0000000000 --- a/src/Components/Analyzers/test/ComponentParametersShouldBePublicCodeFixProviderTest.cs +++ /dev/null @@ -1,126 +0,0 @@ -// 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.CodeAnalysis; -using Microsoft.CodeAnalysis.CodeFixes; -using Microsoft.CodeAnalysis.Diagnostics; -using TestHelper; -using Xunit; - -namespace Microsoft.AspNetCore.Components.Analyzers.Test -{ - public class ComponentParametersShouldBePublicCodeFixProviderTest : CodeFixVerifier - { - [Fact] - public void IgnoresPrivatePropertiesWithoutParameterAttribute() - { - var test = @" - namespace ConsoleApplication1 - { - class TypeName - { - private string MyProperty { get; set; } - } - }" + ComponentsTestDeclarations.Source; - - VerifyCSharpDiagnostic(test); - } - - [Fact] - public void AddsDiagnosticAndFixForPrivatePropertiesWithParameterAttribute() - { - var test = @" - namespace ConsoleApplication1 - { - using " + typeof(ParameterAttribute).Namespace + @"; - - class TypeName - { - [Parameter] private string BadProperty1 { get; set; } - } - }" + ComponentsTestDeclarations.Source; - - VerifyCSharpDiagnostic(test, - new DiagnosticResult - { - Id = DiagnosticDescriptors.ComponentParametersShouldBePublic.Id, - Message = "Component parameter 'ConsoleApplication1.TypeName.BadProperty1' should be public.", - Severity = DiagnosticSeverity.Error, - Locations = new[] - { - new DiagnosticResultLocation("Test0.cs", 8, 40) - } - }); - - VerifyCSharpFix(test, @" - namespace ConsoleApplication1 - { - using " + typeof(ParameterAttribute).Namespace + @"; - - class TypeName - { - [Parameter] public string BadProperty1 { get; set; } - } - }" + ComponentsTestDeclarations.Source); - } - - [Fact] - public void IgnoresPublicPropertiesWithNonPublicSetterWithParameterAttribute() - { - var test = @" - namespace ConsoleApplication1 - { - using " + typeof(ParameterAttribute).Namespace + @"; - - class TypeName - { - [Parameter] public string MyProperty1 { get; private set; } - [Parameter] public object MyProperty2 { get; protected set; } - [Parameter] public object MyProperty3 { get; internal set; } - } - }" + ComponentsTestDeclarations.Source; - - VerifyCSharpDiagnostic(test, - new DiagnosticResult - { - Id = DiagnosticDescriptors.ComponentParameterSettersShouldBePublic.Id, - Message = "Component parameter 'ConsoleApplication1.TypeName.MyProperty1' should have a public setter.", - Severity = DiagnosticSeverity.Error, - Locations = new[] - { - new DiagnosticResultLocation("Test0.cs", 8, 39) - } - }, - new DiagnosticResult - { - Id = DiagnosticDescriptors.ComponentParameterSettersShouldBePublic.Id, - Message = "Component parameter 'ConsoleApplication1.TypeName.MyProperty2' should have a public setter.", - Severity = DiagnosticSeverity.Error, - Locations = new[] - { - new DiagnosticResultLocation("Test0.cs", 9, 39) - } - }, - new DiagnosticResult - { - Id = DiagnosticDescriptors.ComponentParameterSettersShouldBePublic.Id, - Message = "Component parameter 'ConsoleApplication1.TypeName.MyProperty3' should have a public setter.", - Severity = DiagnosticSeverity.Error, - Locations = new[] - { - new DiagnosticResultLocation("Test0.cs", 10, 39) - } - }); - } - - protected override CodeFixProvider GetCSharpCodeFixProvider() - { - return new ComponentParametersShouldBePublicCodeFixProvider(); - } - - protected override DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer() - { - return new ComponentParameterAnalyzer(); - } - } -} diff --git a/src/Components/Analyzers/test/ComponentParametersShouldBePublicTest.cs b/src/Components/Analyzers/test/ComponentParametersShouldBePublicTest.cs deleted file mode 100644 index 97b01c4699..0000000000 --- a/src/Components/Analyzers/test/ComponentParametersShouldBePublicTest.cs +++ /dev/null @@ -1,106 +0,0 @@ -// 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.CodeAnalysis; -using Microsoft.CodeAnalysis.Diagnostics; -using TestHelper; -using Xunit; - -namespace Microsoft.AspNetCore.Components.Analyzers -{ - public class ComponentParametersShouldBePublicTest : DiagnosticVerifier - { - [Fact] - public void IgnoresPublicProperties() - { - var test = $@" - namespace ConsoleApplication1 - {{ - using {typeof(ParameterAttribute).Namespace}; - class TypeName - {{ - [Parameter] public string MyProperty {{ get; set; }} - }} - }}" + ComponentsTestDeclarations.Source; - - VerifyCSharpDiagnostic(test); - } - - [Fact] - public void IgnoresPrivateNonParameterProperties() - { - var test = $@" - namespace ConsoleApplication1 - {{ - using {typeof(ParameterAttribute).Namespace}; - class TypeName - {{ - private string MyProperty {{ get; set; }} - }} - }}" + ComponentsTestDeclarations.Source; - - VerifyCSharpDiagnostic(test); - } - - [Fact] - public void ErrorsForNonPublicParameters() - { - var test = $@" - namespace ConsoleApplication1 - {{ - using {typeof(ParameterAttribute).Namespace}; - class TypeName - {{ - [Parameter] string MyProperty1 {{ get; set; }} - [Parameter] private string MyProperty2 {{ get; set; }} - [Parameter] protected string MyProperty3 {{ get; set; }} - [Parameter] internal string MyProperty4 {{ get; set; }} - }} - }}" + ComponentsTestDeclarations.Source; - - VerifyCSharpDiagnostic(test, - new DiagnosticResult - { - Id = DiagnosticDescriptors.ComponentParametersShouldBePublic.Id, - Message = "Component parameter 'ConsoleApplication1.TypeName.MyProperty1' should be public.", - Severity = DiagnosticSeverity.Error, - Locations = new[] - { - new DiagnosticResultLocation("Test0.cs", 7, 32) - } - }, - new DiagnosticResult - { - Id = DiagnosticDescriptors.ComponentParametersShouldBePublic.Id, - Message = "Component parameter 'ConsoleApplication1.TypeName.MyProperty2' should be public.", - Severity = DiagnosticSeverity.Error, - Locations = new[] - { - new DiagnosticResultLocation("Test0.cs", 8, 40) - } - }, - new DiagnosticResult - { - Id = DiagnosticDescriptors.ComponentParametersShouldBePublic.Id, - Message = "Component parameter 'ConsoleApplication1.TypeName.MyProperty3' should be public.", - Severity = DiagnosticSeverity.Error, - Locations = new[] - { - new DiagnosticResultLocation("Test0.cs", 9, 42) - } - }, - new DiagnosticResult - { - Id = DiagnosticDescriptors.ComponentParametersShouldBePublic.Id, - Message = "Component parameter 'ConsoleApplication1.TypeName.MyProperty4' should be public.", - Severity = DiagnosticSeverity.Error, - Locations = new[] - { - new DiagnosticResultLocation("Test0.cs", 10, 41) - } - }); - } - - protected override DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer() => new ComponentParameterAnalyzer(); - } -} diff --git a/src/Components/Analyzers/test/ComponentsTestDeclarations.cs b/src/Components/Analyzers/test/ComponentsTestDeclarations.cs deleted file mode 100644 index 3c71a82566..0000000000 --- a/src/Components/Analyzers/test/ComponentsTestDeclarations.cs +++ /dev/null @@ -1,26 +0,0 @@ -// 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. - -namespace Microsoft.AspNetCore.Components.Analyzers -{ - public static class ComponentsTestDeclarations - { - public static readonly string Source = $@" - namespace {typeof(ParameterAttribute).Namespace} - {{ - public class {typeof(ParameterAttribute).Name} : System.Attribute - {{ - public bool CaptureUnmatchedValues {{ get; set; }} - }} - - public class {typeof(CascadingParameterAttribute).Name} : System.Attribute - {{ - }} - - public interface {typeof(IComponent).Name} - {{ - }} - }} -"; - } -} diff --git a/src/Components/Analyzers/test/Helpers/CodeFixVerifier.Helper.cs b/src/Components/Analyzers/test/Helpers/CodeFixVerifier.Helper.cs deleted file mode 100644 index b523daa09b..0000000000 --- a/src/Components/Analyzers/test/Helpers/CodeFixVerifier.Helper.cs +++ /dev/null @@ -1,90 +0,0 @@ -// 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. - -// Most of the code in this file comes from the default Roslyn Analyzer project template - -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CodeActions; -using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.Simplification; -using System.Collections.Generic; -using System.Linq; -using System.Threading; - -namespace TestHelper -{ - /// - /// Diagnostic Producer class with extra methods dealing with applying codefixes - /// All methods are static - /// - public abstract partial class CodeFixVerifier : DiagnosticVerifier - { - /// - /// Apply the inputted CodeAction to the inputted document. - /// Meant to be used to apply codefixes. - /// - /// The Document to apply the fix on - /// A CodeAction that will be applied to the Document. - /// A Document with the changes from the CodeAction - private static Document ApplyFix(Document document, CodeAction codeAction) - { - var operations = codeAction.GetOperationsAsync(CancellationToken.None).Result; - var solution = operations.OfType().Single().ChangedSolution; - return solution.GetDocument(document.Id); - } - - /// - /// Compare two collections of Diagnostics,and return a list of any new diagnostics that appear only in the second collection. - /// Note: Considers Diagnostics to be the same if they have the same Ids. In the case of multiple diagnostics with the same Id in a row, - /// this method may not necessarily return the new one. - /// - /// The Diagnostics that existed in the code before the CodeFix was applied - /// The Diagnostics that exist in the code after the CodeFix was applied - /// A list of Diagnostics that only surfaced in the code after the CodeFix was applied - private static IEnumerable GetNewDiagnostics(IEnumerable diagnostics, IEnumerable newDiagnostics) - { - var oldArray = diagnostics.OrderBy(d => d.Location.SourceSpan.Start).ToArray(); - var newArray = newDiagnostics.OrderBy(d => d.Location.SourceSpan.Start).ToArray(); - - int oldIndex = 0; - int newIndex = 0; - - while (newIndex < newArray.Length) - { - if (oldIndex < oldArray.Length && oldArray[oldIndex].Id == newArray[newIndex].Id) - { - ++oldIndex; - ++newIndex; - } - else - { - yield return newArray[newIndex++]; - } - } - } - - /// - /// Get the existing compiler diagnostics on the inputted document. - /// - /// The Document to run the compiler diagnostic analyzers on - /// The compiler diagnostics that were found in the code - private static IEnumerable GetCompilerDiagnostics(Document document) - { - return document.GetSemanticModelAsync().Result.GetDiagnostics(); - } - - /// - /// Given a document, turn it into a string based on the syntax root - /// - /// The Document to be converted to a string - /// A string containing the syntax of the Document after formatting - private static string GetStringFromDocument(Document document) - { - var simplifiedDoc = Simplifier.ReduceAsync(document, Simplifier.Annotation).Result; - var root = simplifiedDoc.GetSyntaxRootAsync().Result; - root = Formatter.Format(root, Formatter.Annotation, simplifiedDoc.Project.Solution.Workspace); - return root.GetText().ToString(); - } - } -} - diff --git a/src/Components/Analyzers/test/Helpers/DiagnosticResult.cs b/src/Components/Analyzers/test/Helpers/DiagnosticResult.cs deleted file mode 100644 index 4e3349ae25..0000000000 --- a/src/Components/Analyzers/test/Helpers/DiagnosticResult.cs +++ /dev/null @@ -1,92 +0,0 @@ -// 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. - -// Most of the code in this file comes from the default Roslyn Analyzer project template - -using Microsoft.CodeAnalysis; -using System; - -namespace TestHelper -{ - /// - /// Location where the diagnostic appears, as determined by path, line number, and column number. - /// - public struct DiagnosticResultLocation - { - public DiagnosticResultLocation(string path, int line, int column) - { - if (line < -1) - { - throw new ArgumentOutOfRangeException(nameof(line), "line must be >= -1"); - } - - if (column < -1) - { - throw new ArgumentOutOfRangeException(nameof(column), "column must be >= -1"); - } - - this.Path = path; - this.Line = line; - this.Column = column; - } - - public string Path { get; } - public int Line { get; } - public int Column { get; } - } - - /// - /// Struct that stores information about a Diagnostic appearing in a source - /// - public struct DiagnosticResult - { - private DiagnosticResultLocation[] locations; - - public DiagnosticResultLocation[] Locations - { - get - { - if (this.locations == null) - { - this.locations = new DiagnosticResultLocation[] { }; - } - return this.locations; - } - - set - { - this.locations = value; - } - } - - public DiagnosticSeverity Severity { get; set; } - - public string Id { get; set; } - - public string Message { get; set; } - - public string Path - { - get - { - return this.Locations.Length > 0 ? this.Locations[0].Path : ""; - } - } - - public int Line - { - get - { - return this.Locations.Length > 0 ? this.Locations[0].Line : -1; - } - } - - public int Column - { - get - { - return this.Locations.Length > 0 ? this.Locations[0].Column : -1; - } - } - } -} diff --git a/src/Components/Analyzers/test/Helpers/DiagnosticVerifier.Helper.cs b/src/Components/Analyzers/test/Helpers/DiagnosticVerifier.Helper.cs deleted file mode 100644 index b55bf99cf4..0000000000 --- a/src/Components/Analyzers/test/Helpers/DiagnosticVerifier.Helper.cs +++ /dev/null @@ -1,175 +0,0 @@ -// 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. - -// Most of the code in this file comes from the default Roslyn Analyzer project template - -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Text; -using System; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Linq; - -namespace TestHelper -{ - /// - /// Class for turning strings into documents and getting the diagnostics on them - /// All methods are static - /// - public abstract partial class DiagnosticVerifier - { - private static readonly MetadataReference CorlibReference = MetadataReference.CreateFromFile(typeof(object).Assembly.Location); - private static readonly MetadataReference SystemCoreReference = MetadataReference.CreateFromFile(typeof(Enumerable).Assembly.Location); - private static readonly MetadataReference CSharpSymbolsReference = MetadataReference.CreateFromFile(typeof(CSharpCompilation).Assembly.Location); - private static readonly MetadataReference CodeAnalysisReference = MetadataReference.CreateFromFile(typeof(Compilation).Assembly.Location); - - internal static string DefaultFilePathPrefix = "Test"; - internal static string CSharpDefaultFileExt = "cs"; - internal static string VisualBasicDefaultExt = "vb"; - internal static string TestProjectName = "TestProject"; - - #region Get Diagnostics - - /// - /// Given classes in the form of strings, their language, and an IDiagnosticAnalyzer to apply to it, return the diagnostics found in the string after converting it to a document. - /// - /// Classes in the form of strings - /// The language the source classes are in - /// The analyzer to be run on the sources - /// An IEnumerable of Diagnostics that surfaced in the source code, sorted by Location - private static Diagnostic[] GetSortedDiagnostics(string[] sources, string language, DiagnosticAnalyzer analyzer) - { - return GetSortedDiagnosticsFromDocuments(analyzer, GetDocuments(sources, language)); - } - - /// - /// Given an analyzer and a document to apply it to, run the analyzer and gather an array of diagnostics found in it. - /// The returned diagnostics are then ordered by location in the source document. - /// - /// The analyzer to run on the documents - /// The Documents that the analyzer will be run on - /// An IEnumerable of Diagnostics that surfaced in the source code, sorted by Location - protected static Diagnostic[] GetSortedDiagnosticsFromDocuments(DiagnosticAnalyzer analyzer, Document[] documents) - { - var projects = new HashSet(); - foreach (var document in documents) - { - projects.Add(document.Project); - } - - var diagnostics = new List(); - foreach (var project in projects) - { - var compilationWithAnalyzers = project.GetCompilationAsync().Result.WithAnalyzers(ImmutableArray.Create(analyzer)); - var diags = compilationWithAnalyzers.GetAnalyzerDiagnosticsAsync().Result; - foreach (var diag in diags) - { - if (diag.Location == Location.None || diag.Location.IsInMetadata) - { - diagnostics.Add(diag); - } - else - { - for (int i = 0; i < documents.Length; i++) - { - var document = documents[i]; - var tree = document.GetSyntaxTreeAsync().Result; - if (tree == diag.Location.SourceTree) - { - diagnostics.Add(diag); - } - } - } - } - } - - var results = SortDiagnostics(diagnostics); - diagnostics.Clear(); - return results; - } - - /// - /// Sort diagnostics by location in source document - /// - /// The list of Diagnostics to be sorted - /// An IEnumerable containing the Diagnostics in order of Location - private static Diagnostic[] SortDiagnostics(IEnumerable diagnostics) - { - return diagnostics.OrderBy(d => d.Location.SourceSpan.Start).ToArray(); - } - - #endregion - - #region Set up compilation and documents - /// - /// Given an array of strings as sources and a language, turn them into a project and return the documents and spans of it. - /// - /// Classes in the form of strings - /// The language the source code is in - /// A Tuple containing the Documents produced from the sources and their TextSpans if relevant - private static Document[] GetDocuments(string[] sources, string language) - { - if (language != LanguageNames.CSharp && language != LanguageNames.VisualBasic) - { - throw new ArgumentException("Unsupported Language"); - } - - var project = CreateProject(sources, language); - var documents = project.Documents.ToArray(); - - if (sources.Length != documents.Length) - { - throw new InvalidOperationException("Amount of sources did not match amount of Documents created"); - } - - return documents; - } - - /// - /// Create a Document from a string through creating a project that contains it. - /// - /// Classes in the form of a string - /// The language the source code is in - /// A Document created from the source string - protected static Document CreateDocument(string source, string language = LanguageNames.CSharp) - { - return CreateProject(new[] { source }, language).Documents.First(); - } - - /// - /// Create a project using the inputted strings as sources. - /// - /// Classes in the form of strings - /// The language the source code is in - /// A Project created out of the Documents created from the source strings - private static Project CreateProject(string[] sources, string language = LanguageNames.CSharp) - { - string fileNamePrefix = DefaultFilePathPrefix; - string fileExt = language == LanguageNames.CSharp ? CSharpDefaultFileExt : VisualBasicDefaultExt; - - var projectId = ProjectId.CreateNewId(debugName: TestProjectName); - - var solution = new AdhocWorkspace() - .CurrentSolution - .AddProject(projectId, TestProjectName, TestProjectName, language) - .AddMetadataReference(projectId, CorlibReference) - .AddMetadataReference(projectId, SystemCoreReference) - .AddMetadataReference(projectId, CSharpSymbolsReference) - .AddMetadataReference(projectId, CodeAnalysisReference); - - int count = 0; - foreach (var source in sources) - { - var newFileName = fileNamePrefix + count + "." + fileExt; - var documentId = DocumentId.CreateNewId(projectId, debugName: newFileName); - solution = solution.AddDocument(documentId, newFileName, SourceText.From(source)); - count++; - } - return solution.GetProject(projectId); - } - #endregion - } -} - diff --git a/src/Components/Analyzers/test/Microsoft.AspNetCore.Components.Analyzers.Tests.csproj b/src/Components/Analyzers/test/Microsoft.AspNetCore.Components.Analyzers.Tests.csproj deleted file mode 100644 index 10085017d1..0000000000 --- a/src/Components/Analyzers/test/Microsoft.AspNetCore.Components.Analyzers.Tests.csproj +++ /dev/null @@ -1,25 +0,0 @@ - - - - $(DefaultNetCoreTargetFramework) - - - - false - - - - - - - - - - - - - - - - - diff --git a/src/Components/Analyzers/test/TestFiles/ComponentInternalUsageDiagnoticsAnalyzerTest/UsesRenderTreeFrameAsParameter.cs b/src/Components/Analyzers/test/TestFiles/ComponentInternalUsageDiagnoticsAnalyzerTest/UsesRenderTreeFrameAsParameter.cs deleted file mode 100644 index 415030a011..0000000000 --- a/src/Components/Analyzers/test/TestFiles/ComponentInternalUsageDiagnoticsAnalyzerTest/UsesRenderTreeFrameAsParameter.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Microsoft.AspNetCore.Components.RenderTree; - -namespace Microsoft.AspNetCore.Components.Analyzers.Tests.TestFiles.ComponentInternalUsageDiagnoticsAnalyzerTest -{ - class UsesRenderTreeFrameAsParameter - { - private void Test(/*MM*/RenderTreeFrame frame) - { - } - } -} diff --git a/src/Components/Analyzers/test/TestFiles/ComponentInternalUsageDiagnoticsAnalyzerTest/UsesRenderTreeFrameTypeAsLocal.cs b/src/Components/Analyzers/test/TestFiles/ComponentInternalUsageDiagnoticsAnalyzerTest/UsesRenderTreeFrameTypeAsLocal.cs deleted file mode 100644 index bdd40c2df1..0000000000 --- a/src/Components/Analyzers/test/TestFiles/ComponentInternalUsageDiagnoticsAnalyzerTest/UsesRenderTreeFrameTypeAsLocal.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using Microsoft.AspNetCore.Components.RenderTree; - -namespace Microsoft.AspNetCore.Components.Analyzers.Tests.TestFiles.ComponentInternalUsageDiagnoticsAnalyzerTest -{ - class UsesRenderTreeFrameTypeAsLocal - { - private void Test() - { - var test = RenderTreeFrameType./*MM*/Attribute; - GC.KeepAlive(test); - } - - } -} diff --git a/src/Components/Analyzers/test/Verifiers/CodeFixVerifier.cs b/src/Components/Analyzers/test/Verifiers/CodeFixVerifier.cs deleted file mode 100644 index cb6c9d4329..0000000000 --- a/src/Components/Analyzers/test/Verifiers/CodeFixVerifier.cs +++ /dev/null @@ -1,133 +0,0 @@ -// 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. - -// Most of the code in this file comes from the default Roslyn Analyzer project template - -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CodeActions; -using Microsoft.CodeAnalysis.CodeFixes; -using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Formatting; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using Xunit; - -namespace TestHelper -{ - /// - /// Superclass of all Unit tests made for diagnostics with codefixes. - /// Contains methods used to verify correctness of codefixes - /// - public abstract partial class CodeFixVerifier : DiagnosticVerifier - { - /// - /// Returns the codefix being tested (C#) - to be implemented in non-abstract class - /// - /// The CodeFixProvider to be used for CSharp code - protected virtual CodeFixProvider GetCSharpCodeFixProvider() - { - return null; - } - - /// - /// Returns the codefix being tested (VB) - to be implemented in non-abstract class - /// - /// The CodeFixProvider to be used for VisualBasic code - protected virtual CodeFixProvider GetBasicCodeFixProvider() - { - return null; - } - - /// - /// Called to test a C# codefix when applied on the inputted string as a source - /// - /// A class in the form of a string before the CodeFix was applied to it - /// A class in the form of a string after the CodeFix was applied to it - /// Index determining which codefix to apply if there are multiple - /// A bool controlling whether or not the test will fail if the CodeFix introduces other warnings after being applied - protected void VerifyCSharpFix(string oldSource, string newSource, int? codeFixIndex = null, bool allowNewCompilerDiagnostics = false) - { - VerifyFix(LanguageNames.CSharp, GetCSharpDiagnosticAnalyzer(), GetCSharpCodeFixProvider(), oldSource, newSource, codeFixIndex, allowNewCompilerDiagnostics); - } - - /// - /// Called to test a VB codefix when applied on the inputted string as a source - /// - /// A class in the form of a string before the CodeFix was applied to it - /// A class in the form of a string after the CodeFix was applied to it - /// Index determining which codefix to apply if there are multiple - /// A bool controlling whether or not the test will fail if the CodeFix introduces other warnings after being applied - protected void VerifyBasicFix(string oldSource, string newSource, int? codeFixIndex = null, bool allowNewCompilerDiagnostics = false) - { - VerifyFix(LanguageNames.VisualBasic, GetBasicDiagnosticAnalyzer(), GetBasicCodeFixProvider(), oldSource, newSource, codeFixIndex, allowNewCompilerDiagnostics); - } - - /// - /// General verifier for codefixes. - /// Creates a Document from the source string, then gets diagnostics on it and applies the relevant codefixes. - /// Then gets the string after the codefix is applied and compares it with the expected result. - /// Note: If any codefix causes new diagnostics to show up, the test fails unless allowNewCompilerDiagnostics is set to true. - /// - /// The language the source code is in - /// The analyzer to be applied to the source code - /// The codefix to be applied to the code wherever the relevant Diagnostic is found - /// A class in the form of a string before the CodeFix was applied to it - /// A class in the form of a string after the CodeFix was applied to it - /// Index determining which codefix to apply if there are multiple - /// A bool controlling whether or not the test will fail if the CodeFix introduces other warnings after being applied - private void VerifyFix(string language, DiagnosticAnalyzer analyzer, CodeFixProvider codeFixProvider, string oldSource, string newSource, int? codeFixIndex, bool allowNewCompilerDiagnostics) - { - var document = CreateDocument(oldSource, language); - var analyzerDiagnostics = GetSortedDiagnosticsFromDocuments(analyzer, new[] { document }); - var compilerDiagnostics = GetCompilerDiagnostics(document); - var attempts = analyzerDiagnostics.Length; - - for (int i = 0; i < attempts; ++i) - { - var actions = new List(); - var context = new CodeFixContext(document, analyzerDiagnostics[0], (a, d) => actions.Add(a), CancellationToken.None); - codeFixProvider.RegisterCodeFixesAsync(context).Wait(); - - if (!actions.Any()) - { - break; - } - - if (codeFixIndex != null) - { - document = ApplyFix(document, actions.ElementAt((int)codeFixIndex)); - break; - } - - document = ApplyFix(document, actions.ElementAt(0)); - analyzerDiagnostics = GetSortedDiagnosticsFromDocuments(analyzer, new[] { document }); - - var newCompilerDiagnostics = GetNewDiagnostics(compilerDiagnostics, GetCompilerDiagnostics(document)); - - //check if applying the code fix introduced any new compiler diagnostics - if (!allowNewCompilerDiagnostics && newCompilerDiagnostics.Any()) - { - // Format and get the compiler diagnostics again so that the locations make sense in the output - document = document.WithSyntaxRoot(Formatter.Format(document.GetSyntaxRootAsync().Result, Formatter.Annotation, document.Project.Solution.Workspace)); - newCompilerDiagnostics = GetNewDiagnostics(compilerDiagnostics, GetCompilerDiagnostics(document)); - - Assert.True(false, - string.Format("Fix introduced new compiler diagnostics:\r\n{0}\r\n\r\nNew document:\r\n{1}\r\n", - string.Join("\r\n", newCompilerDiagnostics.Select(d => d.ToString())), - document.GetSyntaxRootAsync().Result.ToFullString())); - } - - //check if there are analyzer diagnostics left after the code fix - if (!analyzerDiagnostics.Any()) - { - break; - } - } - - //after applying all of the code fixes, compare the resulting string to the inputted one - var actual = GetStringFromDocument(document); - Assert.Equal(newSource, actual); - } - } -} diff --git a/src/Components/Analyzers/test/Verifiers/DiagnosticVerifier.cs b/src/Components/Analyzers/test/Verifiers/DiagnosticVerifier.cs deleted file mode 100644 index f56d4ff93d..0000000000 --- a/src/Components/Analyzers/test/Verifiers/DiagnosticVerifier.cs +++ /dev/null @@ -1,274 +0,0 @@ -// 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. - -// Most of the code in this file comes from the default Roslyn Analyzer project template - -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Diagnostics; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Xunit; - -namespace TestHelper -{ - /// - /// Superclass of all Unit Tests for DiagnosticAnalyzers - /// - public abstract partial class DiagnosticVerifier - { - #region To be implemented by Test classes - /// - /// Get the CSharp analyzer being tested - to be implemented in non-abstract class - /// - protected virtual DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer() - { - return null; - } - - /// - /// Get the Visual Basic analyzer being tested (C#) - to be implemented in non-abstract class - /// - protected virtual DiagnosticAnalyzer GetBasicDiagnosticAnalyzer() - { - return null; - } - #endregion - - #region Verifier wrappers - - /// - /// Called to test a C# DiagnosticAnalyzer when applied on the single inputted string as a source - /// Note: input a DiagnosticResult for each Diagnostic expected - /// - /// A class in the form of a string to run the analyzer on - /// DiagnosticResults that should appear after the analyzer is run on the source - protected void VerifyCSharpDiagnostic(string source, params DiagnosticResult[] expected) - { - VerifyDiagnostics(new[] { source }, LanguageNames.CSharp, GetCSharpDiagnosticAnalyzer(), expected); - } - - /// - /// Called to test a VB DiagnosticAnalyzer when applied on the single inputted string as a source - /// Note: input a DiagnosticResult for each Diagnostic expected - /// - /// A class in the form of a string to run the analyzer on - /// DiagnosticResults that should appear after the analyzer is run on the source - protected void VerifyBasicDiagnostic(string source, params DiagnosticResult[] expected) - { - VerifyDiagnostics(new[] { source }, LanguageNames.VisualBasic, GetBasicDiagnosticAnalyzer(), expected); - } - - /// - /// Called to test a C# DiagnosticAnalyzer when applied on the inputted strings as a source - /// Note: input a DiagnosticResult for each Diagnostic expected - /// - /// An array of strings to create source documents from to run the analyzers on - /// DiagnosticResults that should appear after the analyzer is run on the sources - protected void VerifyCSharpDiagnostic(string[] sources, params DiagnosticResult[] expected) - { - VerifyDiagnostics(sources, LanguageNames.CSharp, GetCSharpDiagnosticAnalyzer(), expected); - } - - /// - /// Called to test a VB DiagnosticAnalyzer when applied on the inputted strings as a source - /// Note: input a DiagnosticResult for each Diagnostic expected - /// - /// An array of strings to create source documents from to run the analyzers on - /// DiagnosticResults that should appear after the analyzer is run on the sources - protected void VerifyBasicDiagnostic(string[] sources, params DiagnosticResult[] expected) - { - VerifyDiagnostics(sources, LanguageNames.VisualBasic, GetBasicDiagnosticAnalyzer(), expected); - } - - /// - /// General method that gets a collection of actual diagnostics found in the source after the analyzer is run, - /// then verifies each of them. - /// - /// An array of strings to create source documents from to run the analyzers on - /// The language of the classes represented by the source strings - /// The analyzer to be run on the source code - /// DiagnosticResults that should appear after the analyzer is run on the sources - private void VerifyDiagnostics(string[] sources, string language, DiagnosticAnalyzer analyzer, params DiagnosticResult[] expected) - { - var diagnostics = GetSortedDiagnostics(sources, language, analyzer); - VerifyDiagnosticResults(diagnostics, analyzer, expected); - } - - #endregion - - #region Actual comparisons and verifications - /// - /// Checks each of the actual Diagnostics found and compares them with the corresponding DiagnosticResult in the array of expected results. - /// Diagnostics are considered equal only if the DiagnosticResultLocation, Id, Severity, and Message of the DiagnosticResult match the actual diagnostic. - /// - /// The Diagnostics found by the compiler after running the analyzer on the source code - /// The analyzer that was being run on the sources - /// Diagnostic Results that should have appeared in the code - private static void VerifyDiagnosticResults(IEnumerable actualResults, DiagnosticAnalyzer analyzer, params DiagnosticResult[] expectedResults) - { - int expectedCount = expectedResults.Count(); - int actualCount = actualResults.Count(); - - if (expectedCount != actualCount) - { - string diagnosticsOutput = actualResults.Any() ? FormatDiagnostics(analyzer, actualResults.ToArray()) : " NONE."; - - Assert.True(false, - string.Format("Mismatch between number of diagnostics returned, expected \"{0}\" actual \"{1}\"\r\n\r\nDiagnostics:\r\n{2}\r\n", expectedCount, actualCount, diagnosticsOutput)); - } - - for (int i = 0; i < expectedResults.Length; i++) - { - var actual = actualResults.ElementAt(i); - var expected = expectedResults[i]; - - if (expected.Line == -1 && expected.Column == -1) - { - if (actual.Location != Location.None) - { - Assert.True(false, - string.Format("Expected:\nA project diagnostic with No location\nActual:\n{0}", - FormatDiagnostics(analyzer, actual))); - } - } - else - { - VerifyDiagnosticLocation(analyzer, actual, actual.Location, expected.Locations.First()); - var additionalLocations = actual.AdditionalLocations.ToArray(); - - if (additionalLocations.Length != expected.Locations.Length - 1) - { - Assert.True(false, - string.Format("Expected {0} additional locations but got {1} for Diagnostic:\r\n {2}\r\n", - expected.Locations.Length - 1, additionalLocations.Length, - FormatDiagnostics(analyzer, actual))); - } - - for (int j = 0; j < additionalLocations.Length; ++j) - { - VerifyDiagnosticLocation(analyzer, actual, additionalLocations[j], expected.Locations[j + 1]); - } - } - - if (actual.Id != expected.Id) - { - Assert.True(false, - string.Format("Expected diagnostic id to be \"{0}\" was \"{1}\"\r\n\r\nDiagnostic:\r\n {2}\r\n", - expected.Id, actual.Id, FormatDiagnostics(analyzer, actual))); - } - - if (actual.Severity != expected.Severity) - { - Assert.True(false, - string.Format("Expected diagnostic severity to be \"{0}\" was \"{1}\"\r\n\r\nDiagnostic:\r\n {2}\r\n", - expected.Severity, actual.Severity, FormatDiagnostics(analyzer, actual))); - } - - if (actual.GetMessage() != expected.Message) - { - Assert.True(false, - string.Format("Expected diagnostic message to be \"{0}\" was \"{1}\"\r\n\r\nDiagnostic:\r\n {2}\r\n", - expected.Message, actual.GetMessage(), FormatDiagnostics(analyzer, actual))); - } - } - } - - /// - /// Helper method to VerifyDiagnosticResult that checks the location of a diagnostic and compares it with the location in the expected DiagnosticResult. - /// - /// The analyzer that was being run on the sources - /// The diagnostic that was found in the code - /// The Location of the Diagnostic found in the code - /// The DiagnosticResultLocation that should have been found - private static void VerifyDiagnosticLocation(DiagnosticAnalyzer analyzer, Diagnostic diagnostic, Location actual, DiagnosticResultLocation expected) - { - var actualSpan = actual.GetLineSpan(); - - Assert.True(actualSpan.Path == expected.Path || (actualSpan.Path != null && actualSpan.Path.Contains("Test0.") && expected.Path.Contains("Test.")), - string.Format("Expected diagnostic to be in file \"{0}\" was actually in file \"{1}\"\r\n\r\nDiagnostic:\r\n {2}\r\n", - expected.Path, actualSpan.Path, FormatDiagnostics(analyzer, diagnostic))); - - var actualLinePosition = actualSpan.StartLinePosition; - - // Only check line position if there is an actual line in the real diagnostic - if (actualLinePosition.Line > 0) - { - if (actualLinePosition.Line + 1 != expected.Line) - { - Assert.True(false, - string.Format("Expected diagnostic to be on line \"{0}\" was actually on line \"{1}\"\r\n\r\nDiagnostic:\r\n {2}\r\n", - expected.Line, actualLinePosition.Line + 1, FormatDiagnostics(analyzer, diagnostic))); - } - } - - // Only check column position if there is an actual column position in the real diagnostic - if (actualLinePosition.Character > 0) - { - if (actualLinePosition.Character + 1 != expected.Column) - { - Assert.True(false, - string.Format("Expected diagnostic to start at column \"{0}\" was actually at column \"{1}\"\r\n\r\nDiagnostic:\r\n {2}\r\n", - expected.Column, actualLinePosition.Character + 1, FormatDiagnostics(analyzer, diagnostic))); - } - } - } - #endregion - - #region Formatting Diagnostics - /// - /// Helper method to format a Diagnostic into an easily readable string - /// - /// The analyzer that this verifier tests - /// The Diagnostics to be formatted - /// The Diagnostics formatted as a string - private static string FormatDiagnostics(DiagnosticAnalyzer analyzer, params Diagnostic[] diagnostics) - { - var builder = new StringBuilder(); - for (int i = 0; i < diagnostics.Length; ++i) - { - builder.AppendLine("// " + diagnostics[i].ToString()); - - var analyzerType = analyzer.GetType(); - var rules = analyzer.SupportedDiagnostics; - - foreach (var rule in rules) - { - if (rule != null && rule.Id == diagnostics[i].Id) - { - var location = diagnostics[i].Location; - if (location == Location.None) - { - builder.AppendFormat("GetGlobalResult({0}.{1})", analyzerType.Name, rule.Id); - } - else - { - Assert.True(location.IsInSource, - $"Test base does not currently handle diagnostics in metadata locations. Diagnostic in metadata: {diagnostics[i]}\r\n"); - - string resultMethodName = diagnostics[i].Location.SourceTree.FilePath.EndsWith(".cs") ? "GetCSharpResultAt" : "GetBasicResultAt"; - var linePosition = diagnostics[i].Location.GetLineSpan().StartLinePosition; - - builder.AppendFormat("{0}({1}, {2}, {3}.{4})", - resultMethodName, - linePosition.Line + 1, - linePosition.Character + 1, - analyzerType.Name, - rule.Id); - } - - if (i != diagnostics.Length - 1) - { - builder.Append(','); - } - - builder.AppendLine(); - break; - } - } - } - return builder.ToString(); - } - #endregion - } -} diff --git a/src/Components/Authorization/ref/Microsoft.AspNetCore.Components.Authorization.csproj b/src/Components/Authorization/ref/Microsoft.AspNetCore.Components.Authorization.csproj deleted file mode 100644 index 513c24575d..0000000000 --- a/src/Components/Authorization/ref/Microsoft.AspNetCore.Components.Authorization.csproj +++ /dev/null @@ -1,16 +0,0 @@ - - - - netstandard2.0;$(DefaultNetCoreTargetFramework) - - - - - - - - - - - - diff --git a/src/Components/Authorization/ref/Microsoft.AspNetCore.Components.Authorization.netcoreapp.cs b/src/Components/Authorization/ref/Microsoft.AspNetCore.Components.Authorization.netcoreapp.cs deleted file mode 100644 index ca0535937a..0000000000 --- a/src/Components/Authorization/ref/Microsoft.AspNetCore.Components.Authorization.netcoreapp.cs +++ /dev/null @@ -1,68 +0,0 @@ -// 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. - -namespace Microsoft.AspNetCore.Components.Authorization -{ - public partial class AuthenticationState - { - public AuthenticationState(System.Security.Claims.ClaimsPrincipal user) { } - public System.Security.Claims.ClaimsPrincipal User { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - } - public delegate void AuthenticationStateChangedHandler(System.Threading.Tasks.Task task); - public abstract partial class AuthenticationStateProvider - { - protected AuthenticationStateProvider() { } - public event Microsoft.AspNetCore.Components.Authorization.AuthenticationStateChangedHandler AuthenticationStateChanged { add { } remove { } } - public abstract System.Threading.Tasks.Task GetAuthenticationStateAsync(); - protected void NotifyAuthenticationStateChanged(System.Threading.Tasks.Task task) { } - } - public sealed partial class AuthorizeRouteView : Microsoft.AspNetCore.Components.RouteView - { - public AuthorizeRouteView() { } - [Microsoft.AspNetCore.Components.ParameterAttribute] - public Microsoft.AspNetCore.Components.RenderFragment Authorizing { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } - [Microsoft.AspNetCore.Components.ParameterAttribute] - public Microsoft.AspNetCore.Components.RenderFragment NotAuthorized { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } - protected override void Render(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder builder) { } - } - public partial class AuthorizeView : Microsoft.AspNetCore.Components.Authorization.AuthorizeViewCore - { - public AuthorizeView() { } - [Microsoft.AspNetCore.Components.ParameterAttribute] - public string Policy { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } - [Microsoft.AspNetCore.Components.ParameterAttribute] - public string Roles { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } - protected override Microsoft.AspNetCore.Authorization.IAuthorizeData[] GetAuthorizeData() { throw null; } - } - public abstract partial class AuthorizeViewCore : Microsoft.AspNetCore.Components.ComponentBase - { - protected AuthorizeViewCore() { } - [Microsoft.AspNetCore.Components.ParameterAttribute] - public Microsoft.AspNetCore.Components.RenderFragment Authorized { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } - [Microsoft.AspNetCore.Components.ParameterAttribute] - public Microsoft.AspNetCore.Components.RenderFragment Authorizing { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } - [Microsoft.AspNetCore.Components.ParameterAttribute] - public Microsoft.AspNetCore.Components.RenderFragment ChildContent { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } - [Microsoft.AspNetCore.Components.ParameterAttribute] - public Microsoft.AspNetCore.Components.RenderFragment NotAuthorized { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } - [Microsoft.AspNetCore.Components.ParameterAttribute] - public object Resource { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } - protected override void BuildRenderTree(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder builder) { } - protected abstract Microsoft.AspNetCore.Authorization.IAuthorizeData[] GetAuthorizeData(); - [System.Diagnostics.DebuggerStepThroughAttribute] - protected override System.Threading.Tasks.Task OnParametersSetAsync() { throw null; } - } - public partial class CascadingAuthenticationState : Microsoft.AspNetCore.Components.ComponentBase, System.IDisposable - { - public CascadingAuthenticationState() { } - [Microsoft.AspNetCore.Components.ParameterAttribute] - public Microsoft.AspNetCore.Components.RenderFragment ChildContent { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } - protected override void BuildRenderTree(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder) { } - protected override void OnInitialized() { } - void System.IDisposable.Dispose() { } - } - public partial interface IHostEnvironmentAuthenticationStateProvider - { - void SetAuthenticationState(System.Threading.Tasks.Task authenticationStateTask); - } -} diff --git a/src/Components/Authorization/ref/Microsoft.AspNetCore.Components.Authorization.netstandard2.0.cs b/src/Components/Authorization/ref/Microsoft.AspNetCore.Components.Authorization.netstandard2.0.cs deleted file mode 100644 index ca0535937a..0000000000 --- a/src/Components/Authorization/ref/Microsoft.AspNetCore.Components.Authorization.netstandard2.0.cs +++ /dev/null @@ -1,68 +0,0 @@ -// 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. - -namespace Microsoft.AspNetCore.Components.Authorization -{ - public partial class AuthenticationState - { - public AuthenticationState(System.Security.Claims.ClaimsPrincipal user) { } - public System.Security.Claims.ClaimsPrincipal User { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - } - public delegate void AuthenticationStateChangedHandler(System.Threading.Tasks.Task task); - public abstract partial class AuthenticationStateProvider - { - protected AuthenticationStateProvider() { } - public event Microsoft.AspNetCore.Components.Authorization.AuthenticationStateChangedHandler AuthenticationStateChanged { add { } remove { } } - public abstract System.Threading.Tasks.Task GetAuthenticationStateAsync(); - protected void NotifyAuthenticationStateChanged(System.Threading.Tasks.Task task) { } - } - public sealed partial class AuthorizeRouteView : Microsoft.AspNetCore.Components.RouteView - { - public AuthorizeRouteView() { } - [Microsoft.AspNetCore.Components.ParameterAttribute] - public Microsoft.AspNetCore.Components.RenderFragment Authorizing { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } - [Microsoft.AspNetCore.Components.ParameterAttribute] - public Microsoft.AspNetCore.Components.RenderFragment NotAuthorized { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } - protected override void Render(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder builder) { } - } - public partial class AuthorizeView : Microsoft.AspNetCore.Components.Authorization.AuthorizeViewCore - { - public AuthorizeView() { } - [Microsoft.AspNetCore.Components.ParameterAttribute] - public string Policy { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } - [Microsoft.AspNetCore.Components.ParameterAttribute] - public string Roles { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } - protected override Microsoft.AspNetCore.Authorization.IAuthorizeData[] GetAuthorizeData() { throw null; } - } - public abstract partial class AuthorizeViewCore : Microsoft.AspNetCore.Components.ComponentBase - { - protected AuthorizeViewCore() { } - [Microsoft.AspNetCore.Components.ParameterAttribute] - public Microsoft.AspNetCore.Components.RenderFragment Authorized { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } - [Microsoft.AspNetCore.Components.ParameterAttribute] - public Microsoft.AspNetCore.Components.RenderFragment Authorizing { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } - [Microsoft.AspNetCore.Components.ParameterAttribute] - public Microsoft.AspNetCore.Components.RenderFragment ChildContent { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } - [Microsoft.AspNetCore.Components.ParameterAttribute] - public Microsoft.AspNetCore.Components.RenderFragment NotAuthorized { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } - [Microsoft.AspNetCore.Components.ParameterAttribute] - public object Resource { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } - protected override void BuildRenderTree(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder builder) { } - protected abstract Microsoft.AspNetCore.Authorization.IAuthorizeData[] GetAuthorizeData(); - [System.Diagnostics.DebuggerStepThroughAttribute] - protected override System.Threading.Tasks.Task OnParametersSetAsync() { throw null; } - } - public partial class CascadingAuthenticationState : Microsoft.AspNetCore.Components.ComponentBase, System.IDisposable - { - public CascadingAuthenticationState() { } - [Microsoft.AspNetCore.Components.ParameterAttribute] - public Microsoft.AspNetCore.Components.RenderFragment ChildContent { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } - protected override void BuildRenderTree(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder) { } - protected override void OnInitialized() { } - void System.IDisposable.Dispose() { } - } - public partial interface IHostEnvironmentAuthenticationStateProvider - { - void SetAuthenticationState(System.Threading.Tasks.Task authenticationStateTask); - } -} diff --git a/src/Components/Authorization/src/AttributeAuthorizeDataCache.cs b/src/Components/Authorization/src/AttributeAuthorizeDataCache.cs deleted file mode 100644 index c1495fb303..0000000000 --- a/src/Components/Authorization/src/AttributeAuthorizeDataCache.cs +++ /dev/null @@ -1,41 +0,0 @@ -// 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.Collections.Concurrent; -using System.Linq; -using Microsoft.AspNetCore.Authorization; - -namespace Microsoft.AspNetCore.Components.Authorization -{ - internal static class AttributeAuthorizeDataCache - { - private static ConcurrentDictionary _cache - = new ConcurrentDictionary(); - - public static IAuthorizeData[] GetAuthorizeDataForType(Type type) - { - IAuthorizeData[] result; - if (!_cache.TryGetValue(type, out result)) - { - result = ComputeAuthorizeDataForType(type); - _cache[type] = result; // Safe race - doesn't matter if it overwrites - } - - return result; - } - - private static IAuthorizeData[] ComputeAuthorizeDataForType(Type type) - { - // Allow Anonymous skips all authorization - var allAttributes = type.GetCustomAttributes(inherit: true); - if (allAttributes.OfType().Any()) - { - return null; - } - - var authorizeDataAttributes = allAttributes.OfType().ToArray(); - return authorizeDataAttributes.Length > 0 ? authorizeDataAttributes : null; - } - } -} diff --git a/src/Components/Authorization/src/AuthenticationState.cs b/src/Components/Authorization/src/AuthenticationState.cs deleted file mode 100644 index 6a05dce35d..0000000000 --- a/src/Components/Authorization/src/AuthenticationState.cs +++ /dev/null @@ -1,28 +0,0 @@ -// 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.Security.Claims; - -namespace Microsoft.AspNetCore.Components.Authorization -{ - /// - /// Provides information about the currently authenticated user, if any. - /// - public class AuthenticationState - { - /// - /// Constructs an instance of . - /// - /// A representing the user. - public AuthenticationState(ClaimsPrincipal user) - { - User = user ?? throw new ArgumentNullException(nameof(user)); - } - - /// - /// Gets a that describes the current user. - /// - public ClaimsPrincipal User { get; } - } -} diff --git a/src/Components/Authorization/src/AuthenticationStateProvider.cs b/src/Components/Authorization/src/AuthenticationStateProvider.cs deleted file mode 100644 index 6fc9af07c7..0000000000 --- a/src/Components/Authorization/src/AuthenticationStateProvider.cs +++ /dev/null @@ -1,46 +0,0 @@ -// 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; - -namespace Microsoft.AspNetCore.Components.Authorization -{ - /// - /// Provides information about the authentication state of the current user. - /// - public abstract class AuthenticationStateProvider - { - /// - /// Asynchronously gets an that describes the current user. - /// - /// A task that, when resolved, gives an instance that describes the current user. - public abstract Task GetAuthenticationStateAsync(); - - /// - /// An event that provides notification when the - /// has changed. For example, this event may be raised if a user logs in or out. - /// - public event AuthenticationStateChangedHandler AuthenticationStateChanged; - - /// - /// Raises the event. - /// - /// A that supplies the updated . - protected void NotifyAuthenticationStateChanged(Task task) - { - if (task == null) - { - throw new ArgumentNullException(nameof(task)); - } - - AuthenticationStateChanged?.Invoke(task); - } - } - - /// - /// A handler for the event. - /// - /// A that supplies the updated . - public delegate void AuthenticationStateChangedHandler(Task task); -} diff --git a/src/Components/Authorization/src/AuthorizeDataAdapter.cs b/src/Components/Authorization/src/AuthorizeDataAdapter.cs deleted file mode 100644 index 55d369f9af..0000000000 --- a/src/Components/Authorization/src/AuthorizeDataAdapter.cs +++ /dev/null @@ -1,39 +0,0 @@ -// 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 Microsoft.AspNetCore.Authorization; - -namespace Microsoft.AspNetCore.Components.Authorization -{ - // This is so the AuthorizeView can avoid implementing IAuthorizeData (even privately) - internal class AuthorizeDataAdapter : IAuthorizeData - { - private readonly AuthorizeView _component; - - public AuthorizeDataAdapter(AuthorizeView component) - { - _component = component ?? throw new ArgumentNullException(nameof(component)); - } - - public string Policy - { - get => _component.Policy; - set => throw new NotSupportedException(); - } - - public string Roles - { - get => _component.Roles; - set => throw new NotSupportedException(); - } - - // AuthorizeView doesn't expose any such parameter, as it wouldn't be used anyway, - // since we already have the ClaimsPrincipal by the time AuthorizeView gets involved. - public string AuthenticationSchemes - { - get => null; - set => throw new NotSupportedException(); - } - } -} diff --git a/src/Components/Authorization/src/AuthorizeRouteView.cs b/src/Components/Authorization/src/AuthorizeRouteView.cs deleted file mode 100644 index 2d7ea76698..0000000000 --- a/src/Components/Authorization/src/AuthorizeRouteView.cs +++ /dev/null @@ -1,117 +0,0 @@ -// 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.Threading.Tasks; -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Components.Rendering; - -namespace Microsoft.AspNetCore.Components.Authorization -{ - /// - /// Combines the behaviors of and , - /// so that it displays the page matching the specified route but only if the user - /// is authorized to see it. - /// - /// Additionally, this component supplies a cascading parameter of type , - /// which makes the user's current authentication state available to descendants. - /// - public sealed class AuthorizeRouteView : RouteView - { - // We expect applications to supply their own authorizing/not-authorized content, but - // it's better to have defaults than to make the parameters mandatory because in some - // cases they will never be used (e.g., "authorizing" in out-of-box server-side Blazor) - private static readonly RenderFragment _defaultNotAuthorizedContent - = state => builder => builder.AddContent(0, "Not authorized"); - private static readonly RenderFragment _defaultAuthorizingContent - = builder => builder.AddContent(0, "Authorizing..."); - - private readonly RenderFragment _renderAuthorizeRouteViewCoreDelegate; - private readonly RenderFragment _renderAuthorizedDelegate; - private readonly RenderFragment _renderNotAuthorizedDelegate; - private readonly RenderFragment _renderAuthorizingDelegate; - - public AuthorizeRouteView() - { - // Cache the rendering delegates so that we only construct new closure instances - // when they are actually used (e.g., we never prepare a RenderFragment bound to - // the NotAuthorized content except when you are displaying that particular state) - RenderFragment renderBaseRouteViewDelegate = builder => base.Render(builder); - _renderAuthorizedDelegate = authenticateState => renderBaseRouteViewDelegate; - _renderNotAuthorizedDelegate = authenticationState => builder => RenderNotAuthorizedInDefaultLayout(builder, authenticationState); - _renderAuthorizingDelegate = RenderAuthorizingInDefaultLayout; - _renderAuthorizeRouteViewCoreDelegate = RenderAuthorizeRouteViewCore; - } - - /// - /// The content that will be displayed if the user is not authorized. - /// - [Parameter] - public RenderFragment NotAuthorized { get; set; } - - /// - /// The content that will be displayed while asynchronous authorization is in progress. - /// - [Parameter] - public RenderFragment Authorizing { get; set; } - - [CascadingParameter] - private Task ExistingCascadedAuthenticationState { get; set; } - - /// - protected override void Render(RenderTreeBuilder builder) - { - if (ExistingCascadedAuthenticationState != null) - { - // If this component is already wrapped in a (or another - // compatible provider), then don't interfere with the cascaded authentication state. - _renderAuthorizeRouteViewCoreDelegate(builder); - } - else - { - // Otherwise, implicitly wrap the output in a - builder.OpenComponent(0); - builder.AddAttribute(1, nameof(CascadingAuthenticationState.ChildContent), _renderAuthorizeRouteViewCoreDelegate); - builder.CloseComponent(); - } - } - - private void RenderAuthorizeRouteViewCore(RenderTreeBuilder builder) - { - builder.OpenComponent(0); - builder.AddAttribute(1, nameof(AuthorizeRouteViewCore.RouteData), RouteData); - builder.AddAttribute(2, nameof(AuthorizeRouteViewCore.Authorized), _renderAuthorizedDelegate); - builder.AddAttribute(3, nameof(AuthorizeRouteViewCore.Authorizing), _renderAuthorizingDelegate); - builder.AddAttribute(4, nameof(AuthorizeRouteViewCore.NotAuthorized), _renderNotAuthorizedDelegate); - builder.CloseComponent(); - } - - private void RenderContentInDefaultLayout(RenderTreeBuilder builder, RenderFragment content) - { - builder.OpenComponent(0); - builder.AddAttribute(1, nameof(LayoutView.Layout), DefaultLayout); - builder.AddAttribute(2, nameof(LayoutView.ChildContent), content); - builder.CloseComponent(); - } - - private void RenderNotAuthorizedInDefaultLayout(RenderTreeBuilder builder, AuthenticationState authenticationState) - { - var content = NotAuthorized ?? _defaultNotAuthorizedContent; - RenderContentInDefaultLayout(builder, content(authenticationState)); - } - - private void RenderAuthorizingInDefaultLayout(RenderTreeBuilder builder) - { - var content = Authorizing ?? _defaultAuthorizingContent; - RenderContentInDefaultLayout(builder, content); - } - - private class AuthorizeRouteViewCore : AuthorizeViewCore - { - [Parameter] - public RouteData RouteData { get; set; } - - protected override IAuthorizeData[] GetAuthorizeData() - => AttributeAuthorizeDataCache.GetAuthorizeDataForType(RouteData.PageType); - } - } -} diff --git a/src/Components/Authorization/src/AuthorizeView.cs b/src/Components/Authorization/src/AuthorizeView.cs deleted file mode 100644 index b66a00d2a4..0000000000 --- a/src/Components/Authorization/src/AuthorizeView.cs +++ /dev/null @@ -1,39 +0,0 @@ -// 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.AspNetCore.Authorization; - -namespace Microsoft.AspNetCore.Components.Authorization -{ - /// - /// Displays differing content depending on the user's authorization status. - /// - public class AuthorizeView : AuthorizeViewCore - { - private readonly IAuthorizeData[] selfAsAuthorizeData; - - /// - /// Constructs an instance of . - /// - public AuthorizeView() - { - selfAsAuthorizeData = new[] { new AuthorizeDataAdapter(this) }; - } - - /// - /// The policy name that determines whether the content can be displayed. - /// - [Parameter] public string Policy { get; set; } - - /// - /// A comma delimited list of roles that are allowed to display the content. - /// - [Parameter] public string Roles { get; set; } - - /// - /// Gets the data used for authorization. - /// - protected override IAuthorizeData[] GetAuthorizeData() - => selfAsAuthorizeData; - } -} diff --git a/src/Components/Authorization/src/AuthorizeViewCore.cs b/src/Components/Authorization/src/AuthorizeViewCore.cs deleted file mode 100644 index b225bb19bd..0000000000 --- a/src/Components/Authorization/src/AuthorizeViewCore.cs +++ /dev/null @@ -1,136 +0,0 @@ -// 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.Security.Claims; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Components.Rendering; - -namespace Microsoft.AspNetCore.Components.Authorization -{ - /// - /// A base class for components that display differing content depending on the user's authorization status. - /// - public abstract class AuthorizeViewCore : ComponentBase - { - private AuthenticationState currentAuthenticationState; - private bool isAuthorized; - - /// - /// The content that will be displayed if the user is authorized. - /// - [Parameter] public RenderFragment ChildContent { get; set; } - - /// - /// The content that will be displayed if the user is not authorized. - /// - [Parameter] public RenderFragment NotAuthorized { get; set; } - - /// - /// The content that will be displayed if the user is authorized. - /// If you specify a value for this parameter, do not also specify a value for . - /// - [Parameter] public RenderFragment Authorized { get; set; } - - /// - /// The content that will be displayed while asynchronous authorization is in progress. - /// - [Parameter] public RenderFragment Authorizing { get; set; } - - /// - /// The resource to which access is being controlled. - /// - [Parameter] public object Resource { get; set; } - - [CascadingParameter] private Task AuthenticationState { get; set; } - - [Inject] private IAuthorizationPolicyProvider AuthorizationPolicyProvider { get; set; } - - [Inject] private IAuthorizationService AuthorizationService { get; set; } - - /// - protected override void BuildRenderTree(RenderTreeBuilder builder) - { - // We're using the same sequence number for each of the content items here - // so that we can update existing instances if they are the same shape - if (currentAuthenticationState == null) - { - builder.AddContent(0, Authorizing); - } - else if (isAuthorized) - { - var authorized = Authorized ?? ChildContent; - builder.AddContent(0, authorized?.Invoke(currentAuthenticationState)); - } - else - { - builder.AddContent(0, NotAuthorized?.Invoke(currentAuthenticationState)); - } - } - - /// - protected override async Task OnParametersSetAsync() - { - // We allow 'ChildContent' for convenience in basic cases, and 'Authorized' for symmetry - // with 'NotAuthorized' in other cases. Besides naming, they are equivalent. To avoid - // confusion, explicitly prevent the case where both are supplied. - if (ChildContent != null && Authorized != null) - { - throw new InvalidOperationException($"Do not specify both '{nameof(Authorized)}' and '{nameof(ChildContent)}'."); - } - - if (AuthenticationState == null) - { - throw new InvalidOperationException($"Authorization requires a cascading parameter of type Task<{nameof(AuthenticationState)}>. Consider using {typeof(CascadingAuthenticationState).Name} to supply this."); - } - - // First render in pending state - // If the task has already completed, this render will be skipped - currentAuthenticationState = null; - - // Then render in completed state - // Importantly, we *don't* call StateHasChanged between the following async steps, - // otherwise we'd display an incorrect UI state while waiting for IsAuthorizedAsync - currentAuthenticationState = await AuthenticationState; - isAuthorized = await IsAuthorizedAsync(currentAuthenticationState.User); - } - - /// - /// Gets the data required to apply authorization rules. - /// - protected abstract IAuthorizeData[] GetAuthorizeData(); - - private async Task IsAuthorizedAsync(ClaimsPrincipal user) - { - var authorizeData = GetAuthorizeData(); - if (authorizeData == null) - { - // No authorization applies, so no need to consult the authorization service - return true; - } - - EnsureNoAuthenticationSchemeSpecified(authorizeData); - - var policy = await AuthorizationPolicy.CombineAsync( - AuthorizationPolicyProvider, authorizeData); - var result = await AuthorizationService.AuthorizeAsync(user, Resource, policy); - return result.Succeeded; - } - - private static void EnsureNoAuthenticationSchemeSpecified(IAuthorizeData[] authorizeData) - { - // It's not meaningful to specify a nonempty scheme, since by the time Components - // authorization runs, we already have a specific ClaimsPrincipal (we're stateful). - // To avoid any confusion, ensure the developer isn't trying to specify a scheme. - for (var i = 0; i < authorizeData.Length; i++) - { - var entry = authorizeData[i]; - if (!string.IsNullOrEmpty(entry.AuthenticationSchemes)) - { - throw new NotSupportedException($"The authorization data specifies an authentication scheme with value '{entry.AuthenticationSchemes}'. Authentication schemes cannot be specified for components."); - } - } - } - } -} diff --git a/src/Components/Authorization/src/CascadingAuthenticationState.razor b/src/Components/Authorization/src/CascadingAuthenticationState.razor deleted file mode 100644 index 87506d2c61..0000000000 --- a/src/Components/Authorization/src/CascadingAuthenticationState.razor +++ /dev/null @@ -1,36 +0,0 @@ -@implements IDisposable -@inject AuthenticationStateProvider AuthenticationStateProvider - - - -@code { - private Task _currentAuthenticationStateTask; - - /// - /// The content to which the authentication state should be provided. - /// - [Parameter] - public RenderFragment ChildContent { get; set; } - - protected override void OnInitialized() - { - AuthenticationStateProvider.AuthenticationStateChanged += OnAuthenticationStateChanged; - - _currentAuthenticationStateTask = AuthenticationStateProvider - .GetAuthenticationStateAsync(); - } - - private void OnAuthenticationStateChanged(Task newAuthStateTask) - { - _ = InvokeAsync(() => - { - _currentAuthenticationStateTask = newAuthStateTask; - StateHasChanged(); - }); - } - - void IDisposable.Dispose() - { - AuthenticationStateProvider.AuthenticationStateChanged -= OnAuthenticationStateChanged; - } -} diff --git a/src/Components/Authorization/src/IHostEnvironmentAuthenticationStateProvider.cs b/src/Components/Authorization/src/IHostEnvironmentAuthenticationStateProvider.cs deleted file mode 100644 index fc036572a2..0000000000 --- a/src/Components/Authorization/src/IHostEnvironmentAuthenticationStateProvider.cs +++ /dev/null @@ -1,20 +0,0 @@ -// 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.Threading.Tasks; - -namespace Microsoft.AspNetCore.Components.Authorization -{ - /// - /// An interface implemented by classes that can receive authentication - /// state information from the host environment. - /// - public interface IHostEnvironmentAuthenticationStateProvider - { - /// - /// Supplies updated authentication state data to the . - /// - /// A task that resolves with the updated . - void SetAuthenticationState(Task authenticationStateTask); - } -} diff --git a/src/Components/Authorization/src/Microsoft.AspNetCore.Components.Authorization.csproj b/src/Components/Authorization/src/Microsoft.AspNetCore.Components.Authorization.csproj deleted file mode 100644 index 8f3142849a..0000000000 --- a/src/Components/Authorization/src/Microsoft.AspNetCore.Components.Authorization.csproj +++ /dev/null @@ -1,18 +0,0 @@ - - - - netstandard2.0;$(DefaultNetCoreTargetFramework) - $(DefaultNetCoreTargetFramework) - true - Authentication and authorization support for Blazor applications. - true - true - 3.0 - - - - - - - - diff --git a/src/Components/Authorization/test/AuthorizeRouteViewTest.cs b/src/Components/Authorization/test/AuthorizeRouteViewTest.cs deleted file mode 100644 index 5a3a5683c7..0000000000 --- a/src/Components/Authorization/test/AuthorizeRouteViewTest.cs +++ /dev/null @@ -1,356 +0,0 @@ -// 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.Collections.Generic; -using System.Linq; -using System.Security.Claims; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Components.Rendering; -using Microsoft.AspNetCore.Components.RenderTree; -using Microsoft.AspNetCore.Components.Test.Helpers; -using Microsoft.Extensions.DependencyInjection; -using Xunit; - -namespace Microsoft.AspNetCore.Components.Authorization -{ - public class AuthorizeRouteViewTest - { - private readonly static IReadOnlyDictionary EmptyParametersDictionary = new Dictionary(); - private readonly TestAuthenticationStateProvider _authenticationStateProvider; - private readonly TestRenderer _renderer; - private readonly RouteView _authorizeRouteViewComponent; - private readonly int _authorizeRouteViewComponentId; - private readonly TestAuthorizationService _testAuthorizationService; - - public AuthorizeRouteViewTest() - { - _authenticationStateProvider = new TestAuthenticationStateProvider(); - _authenticationStateProvider.CurrentAuthStateTask = Task.FromResult( - new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity()))); - - _testAuthorizationService = new TestAuthorizationService(); - - var serviceCollection = new ServiceCollection(); - serviceCollection.AddSingleton(_authenticationStateProvider); - serviceCollection.AddSingleton(); - serviceCollection.AddSingleton(_testAuthorizationService); - - _renderer = new TestRenderer(serviceCollection.BuildServiceProvider()); - _authorizeRouteViewComponent = new AuthorizeRouteView(); - _authorizeRouteViewComponentId = _renderer.AssignRootComponentId(_authorizeRouteViewComponent); - } - - [Fact] - public void WhenAuthorized_RendersPageInsideLayout() - { - // Arrange - var routeData = new RouteData(typeof(TestPageRequiringAuthorization), new Dictionary - { - { nameof(TestPageRequiringAuthorization.Message), "Hello, world!" } - }); - _testAuthorizationService.NextResult = AuthorizationResult.Success(); - - // Act - _renderer.RenderRootComponent(_authorizeRouteViewComponentId, ParameterView.FromDictionary(new Dictionary - { - { nameof(AuthorizeRouteView.RouteData), routeData }, - { nameof(AuthorizeRouteView.DefaultLayout), typeof(TestLayout) }, - })); - - // Assert: renders layout - var batch = _renderer.Batches.Single(); - var layoutDiff = batch.GetComponentDiffs().Single(); - Assert.Collection(layoutDiff.Edits, - edit => AssertPrependText(batch, edit, "Layout starts here"), - edit => - { - Assert.Equal(RenderTreeEditType.PrependFrame, edit.Type); - AssertFrame.Component(batch.ReferenceFrames[edit.ReferenceFrameIndex]); - }, - edit => AssertPrependText(batch, edit, "Layout ends here")); - - // Assert: renders page - var pageDiff = batch.GetComponentDiffs().Single(); - Assert.Collection(pageDiff.Edits, - edit => AssertPrependText(batch, edit, "Hello from the page with message: Hello, world!")); - } - - [Fact] - public void WhenNotAuthorized_RendersDefaultNotAuthorizedContentInsideLayout() - { - // Arrange - var routeData = new RouteData(typeof(TestPageRequiringAuthorization), EmptyParametersDictionary); - _testAuthorizationService.NextResult = AuthorizationResult.Failed(); - - // Act - _renderer.RenderRootComponent(_authorizeRouteViewComponentId, ParameterView.FromDictionary(new Dictionary - { - { nameof(AuthorizeRouteView.RouteData), routeData }, - { nameof(AuthorizeRouteView.DefaultLayout), typeof(TestLayout) }, - })); - - // Assert: renders layout containing "not authorized" message - var batch = _renderer.Batches.Single(); - var layoutDiff = batch.GetComponentDiffs().Single(); - Assert.Collection(layoutDiff.Edits, - edit => AssertPrependText(batch, edit, "Layout starts here"), - edit => AssertPrependText(batch, edit, "Not authorized"), - edit => AssertPrependText(batch, edit, "Layout ends here")); - } - - [Fact] - public void WhenNotAuthorized_RendersCustomNotAuthorizedContentInsideLayout() - { - // Arrange - var routeData = new RouteData(typeof(TestPageRequiringAuthorization), EmptyParametersDictionary); - _testAuthorizationService.NextResult = AuthorizationResult.Failed(); - _authenticationStateProvider.CurrentAuthStateTask = Task.FromResult(new AuthenticationState( - new ClaimsPrincipal(new TestIdentity { Name = "Bert" }))); - - // Act - RenderFragment customNotAuthorized = - state => builder => builder.AddContent(0, $"Go away, {state.User.Identity.Name}"); - _renderer.RenderRootComponent(_authorizeRouteViewComponentId, ParameterView.FromDictionary(new Dictionary - { - { nameof(AuthorizeRouteView.RouteData), routeData }, - { nameof(AuthorizeRouteView.DefaultLayout), typeof(TestLayout) }, - { nameof(AuthorizeRouteView.NotAuthorized), customNotAuthorized }, - })); - - // Assert: renders layout containing "not authorized" message - var batch = _renderer.Batches.Single(); - var layoutDiff = batch.GetComponentDiffs().Single(); - Assert.Collection(layoutDiff.Edits, - edit => AssertPrependText(batch, edit, "Layout starts here"), - edit => AssertPrependText(batch, edit, "Go away, Bert"), - edit => AssertPrependText(batch, edit, "Layout ends here")); - } - - [Fact] - public async Task WhenAuthorizing_RendersDefaultAuthorizingContentInsideLayout() - { - // Arrange - var routeData = new RouteData(typeof(TestPageRequiringAuthorization), EmptyParametersDictionary); - var authStateTcs = new TaskCompletionSource(); - _authenticationStateProvider.CurrentAuthStateTask = authStateTcs.Task; - RenderFragment customNotAuthorized = - state => builder => builder.AddContent(0, $"Go away, {state.User.Identity.Name}"); - - // Act - var firstRenderTask = _renderer.RenderRootComponentAsync(_authorizeRouteViewComponentId, ParameterView.FromDictionary(new Dictionary - { - { nameof(AuthorizeRouteView.RouteData), routeData }, - { nameof(AuthorizeRouteView.DefaultLayout), typeof(TestLayout) }, - { nameof(AuthorizeRouteView.NotAuthorized), customNotAuthorized }, - })); - - // Assert: renders layout containing "authorizing" message - Assert.False(firstRenderTask.IsCompleted); - var batch = _renderer.Batches.Single(); - var layoutDiff = batch.GetComponentDiffs().Single(); - Assert.Collection(layoutDiff.Edits, - edit => AssertPrependText(batch, edit, "Layout starts here"), - edit => AssertPrependText(batch, edit, "Authorizing..."), - edit => AssertPrependText(batch, edit, "Layout ends here")); - - // Act 2: updates when authorization completes - authStateTcs.SetResult(new AuthenticationState( - new ClaimsPrincipal(new TestIdentity { Name = "Bert" }))); - await firstRenderTask; - - // Assert 2: Only the layout is updated - batch = _renderer.Batches.Skip(1).Single(); - var nonEmptyDiff = batch.DiffsInOrder.Where(d => d.Edits.Any()).Single(); - Assert.Equal(layoutDiff.ComponentId, nonEmptyDiff.ComponentId); - Assert.Collection(nonEmptyDiff.Edits, edit => - { - Assert.Equal(RenderTreeEditType.UpdateText, edit.Type); - Assert.Equal(1, edit.SiblingIndex); - AssertFrame.Text(batch.ReferenceFrames[edit.ReferenceFrameIndex], "Go away, Bert"); - }); - } - - [Fact] - public void WhenAuthorizing_RendersCustomAuthorizingContentInsideLayout() - { - // Arrange - var routeData = new RouteData(typeof(TestPageRequiringAuthorization), EmptyParametersDictionary); - var authStateTcs = new TaskCompletionSource(); - _authenticationStateProvider.CurrentAuthStateTask = authStateTcs.Task; - RenderFragment customAuthorizing = - builder => builder.AddContent(0, "Hold on, we're checking your papers."); - - // Act - var firstRenderTask = _renderer.RenderRootComponentAsync(_authorizeRouteViewComponentId, ParameterView.FromDictionary(new Dictionary - { - { nameof(AuthorizeRouteView.RouteData), routeData }, - { nameof(AuthorizeRouteView.DefaultLayout), typeof(TestLayout) }, - { nameof(AuthorizeRouteView.Authorizing), customAuthorizing }, - })); - - // Assert: renders layout containing "authorizing" message - Assert.False(firstRenderTask.IsCompleted); - var batch = _renderer.Batches.Single(); - var layoutDiff = batch.GetComponentDiffs().Single(); - Assert.Collection(layoutDiff.Edits, - edit => AssertPrependText(batch, edit, "Layout starts here"), - edit => AssertPrependText(batch, edit, "Hold on, we're checking your papers."), - edit => AssertPrependText(batch, edit, "Layout ends here")); - } - - [Fact] - public void WithoutCascadedAuthenticationState_WrapsOutputInCascadingAuthenticationState() - { - // Arrange/Act - var routeData = new RouteData(typeof(TestPageWithNoAuthorization), EmptyParametersDictionary); - _renderer.RenderRootComponent(_authorizeRouteViewComponentId, ParameterView.FromDictionary(new Dictionary - { - { nameof(AuthorizeRouteView.RouteData), routeData } - })); - - // Assert - var batch = _renderer.Batches.Single(); - var componentInstances = batch.ReferenceFrames - .Where(f => f.FrameType == RenderTreeFrameType.Component) - .Select(f => f.Component); - - Assert.Collection(componentInstances, - // This is the hierarchy inside the AuthorizeRouteView, which contains its - // own CascadingAuthenticationState - component => Assert.IsType(component), - component => Assert.IsType>>(component), - component => Assert.IsAssignableFrom(component), - component => Assert.IsType(component), - component => Assert.IsType(component)); - } - - [Fact] - public void WithCascadedAuthenticationState_DoesNotWrapOutputInCascadingAuthenticationState() - { - // Arrange - var routeData = new RouteData(typeof(TestPageWithNoAuthorization), EmptyParametersDictionary); - var rootComponent = new AuthorizeRouteViewWithExistingCascadedAuthenticationState( - _authenticationStateProvider.CurrentAuthStateTask, - routeData); - var rootComponentId = _renderer.AssignRootComponentId(rootComponent); - - // Act - _renderer.RenderRootComponent(rootComponentId); - - // Assert - var batch = _renderer.Batches.Single(); - var componentInstances = batch.ReferenceFrames - .Where(f => f.FrameType == RenderTreeFrameType.Component) - .Select(f => f.Component); - - Assert.Collection(componentInstances, - // This is the externally-supplied cascading value - component => Assert.IsType>>(component), - component => Assert.IsType(component), - - // This is the hierarchy inside the AuthorizeRouteView. It doesn't contain a - // further CascadingAuthenticationState - component => Assert.IsAssignableFrom(component), - component => Assert.IsType(component), - component => Assert.IsType(component)); - } - - [Fact] - public void UpdatesOutputWhenRouteDataChanges() - { - // Arrange/Act 1: Start on some route - // Not asserting about the initial output, as that is covered by other tests - var routeData = new RouteData(typeof(TestPageWithNoAuthorization), EmptyParametersDictionary); - _renderer.RenderRootComponent(_authorizeRouteViewComponentId, ParameterView.FromDictionary(new Dictionary - { - { nameof(AuthorizeRouteView.RouteData), routeData }, - { nameof(AuthorizeRouteView.DefaultLayout), typeof(TestLayout) }, - })); - - // Act 2: Move to another route - var routeData2 = new RouteData(typeof(TestPageRequiringAuthorization), EmptyParametersDictionary); - var render2Task = _renderer.Dispatcher.InvokeAsync(() => _authorizeRouteViewComponent.SetParametersAsync(ParameterView.FromDictionary(new Dictionary - { - { nameof(AuthorizeRouteView.RouteData), routeData2 }, - }))); - - // Assert: we retain the layout instance, and mutate its contents - Assert.True(render2Task.IsCompletedSuccessfully); - Assert.Equal(2, _renderer.Batches.Count); - var batch2 = _renderer.Batches[1]; - var diff = batch2.DiffsInOrder.Where(d => d.Edits.Any()).Single(); - Assert.Collection(diff.Edits, - edit => - { - // Inside the layout, we add the new content - Assert.Equal(RenderTreeEditType.PrependFrame, edit.Type); - Assert.Equal(1, edit.SiblingIndex); - AssertFrame.Text(batch2.ReferenceFrames[edit.ReferenceFrameIndex], "Not authorized"); - }, - edit => - { - // ... and remove the old content - Assert.Equal(RenderTreeEditType.RemoveFrame, edit.Type); - Assert.Equal(2, edit.SiblingIndex); - }); - } - - private static void AssertPrependText(CapturedBatch batch, RenderTreeEdit edit, string text) - { - Assert.Equal(RenderTreeEditType.PrependFrame, edit.Type); - ref var referenceFrame = ref batch.ReferenceFrames[edit.ReferenceFrameIndex]; - AssertFrame.Text(referenceFrame, text); - } - - class TestPageWithNoAuthorization : ComponentBase { } - - [Authorize] - class TestPageRequiringAuthorization : ComponentBase - { - [Parameter] public string Message { get; set; } - - protected override void BuildRenderTree(RenderTreeBuilder builder) - { - builder.AddContent(0, $"Hello from the page with message: {Message}"); - } - } - - class TestLayout : LayoutComponentBase - { - protected override void BuildRenderTree(RenderTreeBuilder builder) - { - builder.AddContent(0, "Layout starts here"); - builder.AddContent(1, Body); - builder.AddContent(2, "Layout ends here"); - } - } - - class AuthorizeRouteViewWithExistingCascadedAuthenticationState : AutoRenderComponent - { - private readonly Task _authenticationState; - private readonly RouteData _routeData; - - public AuthorizeRouteViewWithExistingCascadedAuthenticationState( - Task authenticationState, - RouteData routeData) - { - _authenticationState = authenticationState; - _routeData = routeData; - } - - protected override void BuildRenderTree(RenderTreeBuilder builder) - { - builder.OpenComponent>>(0); - builder.AddAttribute(1, nameof(CascadingValue.Value), _authenticationState); - builder.AddAttribute(2, nameof(CascadingValue.ChildContent), (RenderFragment)(builder => - { - builder.OpenComponent(0); - builder.AddAttribute(1, nameof(AuthorizeRouteView.RouteData), _routeData); - builder.CloseComponent(); - })); - builder.CloseComponent(); - } - } - } -} diff --git a/src/Components/Authorization/test/AuthorizeViewTest.cs b/src/Components/Authorization/test/AuthorizeViewTest.cs deleted file mode 100644 index a28b8808c4..0000000000 --- a/src/Components/Authorization/test/AuthorizeViewTest.cs +++ /dev/null @@ -1,524 +0,0 @@ -// 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.Diagnostics; -using System.Linq; -using System.Security.Claims; -using System.Security.Principal; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Authorization.Infrastructure; -using Microsoft.AspNetCore.Components.Rendering; -using Microsoft.AspNetCore.Components.RenderTree; -using Microsoft.AspNetCore.Components.Test.Helpers; -using Microsoft.Extensions.DependencyInjection; -using Xunit; - -namespace Microsoft.AspNetCore.Components.Authorization -{ - public class AuthorizeViewTest - { - // Nothing should exceed the timeout in a successful run of the the tests, this is just here to catch - // failures. - private static readonly TimeSpan Timeout = Debugger.IsAttached ? System.Threading.Timeout.InfiniteTimeSpan : TimeSpan.FromSeconds(10); - - [Fact] - public void RendersNothingIfNotAuthorized() - { - // Arrange - var authorizationService = new TestAuthorizationService(); - var renderer = CreateTestRenderer(authorizationService); - var rootComponent = WrapInAuthorizeView( - childContent: - context => builder => builder.AddContent(0, "This should not be rendered")); - - // Act - renderer.AssignRootComponentId(rootComponent); - rootComponent.TriggerRender(); - - // Assert - var diff = renderer.Batches.Single().GetComponentDiffs().Single(); - Assert.Empty(diff.Edits); - - // Assert: The IAuthorizationService was given expected criteria - Assert.Collection(authorizationService.AuthorizeCalls, call => - { - Assert.Null(call.user.Identity); - Assert.Null(call.resource); - Assert.Collection(call.requirements, - req => Assert.IsType(req)); - }); - } - - [Fact] - public void RendersNotAuthorizedIfNotAuthorized() - { - // Arrange - var authorizationService = new TestAuthorizationService(); - var renderer = CreateTestRenderer(authorizationService); - var rootComponent = WrapInAuthorizeView( - notAuthorized: - context => builder => builder.AddContent(0, $"You are not authorized, even though we know you are {context.User.Identity.Name}")); - rootComponent.AuthenticationState = CreateAuthenticationState("Nellie"); - - // Act - renderer.AssignRootComponentId(rootComponent); - rootComponent.TriggerRender(); - - // Assert - var diff = renderer.Batches.Single().GetComponentDiffs().Single(); - Assert.Collection(diff.Edits, edit => - { - Assert.Equal(RenderTreeEditType.PrependFrame, edit.Type); - AssertFrame.Text( - renderer.Batches.Single().ReferenceFrames[edit.ReferenceFrameIndex], - "You are not authorized, even though we know you are Nellie"); - }); - - // Assert: The IAuthorizationService was given expected criteria - Assert.Collection(authorizationService.AuthorizeCalls, call => - { - Assert.Equal("Nellie", call.user.Identity.Name); - Assert.Null(call.resource); - Assert.Collection(call.requirements, - req => Assert.IsType(req)); - }); - } - - [Fact] - public void RendersNothingIfAuthorizedButNoChildContentOrAuthorizedProvided() - { - // Arrange - var authorizationService = new TestAuthorizationService(); - authorizationService.NextResult = AuthorizationResult.Success(); - var renderer = CreateTestRenderer(authorizationService); - var rootComponent = WrapInAuthorizeView(); - rootComponent.AuthenticationState = CreateAuthenticationState("Nellie"); - - // Act - renderer.AssignRootComponentId(rootComponent); - rootComponent.TriggerRender(); - - // Assert - var diff = renderer.Batches.Single().GetComponentDiffs().Single(); - Assert.Empty(diff.Edits); - - // Assert: The IAuthorizationService was given expected criteria - Assert.Collection(authorizationService.AuthorizeCalls, call => - { - Assert.Equal("Nellie", call.user.Identity.Name); - Assert.Null(call.resource); - Assert.Collection(call.requirements, - req => Assert.IsType(req)); - }); - } - - [Fact] - public void RendersChildContentIfAuthorized() - { - // Arrange - var authorizationService = new TestAuthorizationService(); - authorizationService.NextResult = AuthorizationResult.Success(); - var renderer = CreateTestRenderer(authorizationService); - var rootComponent = WrapInAuthorizeView( - childContent: context => builder => - builder.AddContent(0, $"You are authenticated as {context.User.Identity.Name}")); - rootComponent.AuthenticationState = CreateAuthenticationState("Nellie"); - - // Act - renderer.AssignRootComponentId(rootComponent); - rootComponent.TriggerRender(); - - // Assert - var diff = renderer.Batches.Single().GetComponentDiffs().Single(); - Assert.Collection(diff.Edits, edit => - { - Assert.Equal(RenderTreeEditType.PrependFrame, edit.Type); - AssertFrame.Text( - renderer.Batches.Single().ReferenceFrames[edit.ReferenceFrameIndex], - "You are authenticated as Nellie"); - }); - - // Assert: The IAuthorizationService was given expected criteria - Assert.Collection(authorizationService.AuthorizeCalls, call => - { - Assert.Equal("Nellie", call.user.Identity.Name); - Assert.Null(call.resource); - Assert.Collection(call.requirements, - req => Assert.IsType(req)); - }); - } - - [Fact] - public void RendersAuthorizedIfAuthorized() - { - // Arrange - var authorizationService = new TestAuthorizationService(); - authorizationService.NextResult = AuthorizationResult.Success(); - var renderer = CreateTestRenderer(authorizationService); - var rootComponent = WrapInAuthorizeView( - authorized: context => builder => - builder.AddContent(0, $"You are authenticated as {context.User.Identity.Name}")); - rootComponent.AuthenticationState = CreateAuthenticationState("Nellie"); - - // Act - renderer.AssignRootComponentId(rootComponent); - rootComponent.TriggerRender(); - - // Assert - var diff = renderer.Batches.Single().GetComponentDiffs().Single(); - Assert.Collection(diff.Edits, edit => - { - Assert.Equal(RenderTreeEditType.PrependFrame, edit.Type); - AssertFrame.Text( - renderer.Batches.Single().ReferenceFrames[edit.ReferenceFrameIndex], - "You are authenticated as Nellie"); - }); - - // Assert: The IAuthorizationService was given expected criteria - Assert.Collection(authorizationService.AuthorizeCalls, call => - { - Assert.Equal("Nellie", call.user.Identity.Name); - Assert.Null(call.resource); - Assert.Collection(call.requirements, - req => Assert.IsType(req)); - }); - } - - [Fact] - public void RespondsToChangeInAuthorizationState() - { - // Arrange - var authorizationService = new TestAuthorizationService(); - authorizationService.NextResult = AuthorizationResult.Success(); - var renderer = CreateTestRenderer(authorizationService); - var rootComponent = WrapInAuthorizeView( - childContent: context => builder => - builder.AddContent(0, $"You are authenticated as {context.User.Identity.Name}")); - rootComponent.AuthenticationState = CreateAuthenticationState("Nellie"); - - // Render in initial state. From other tests, we know this renders - // a single batch with the correct output. - renderer.AssignRootComponentId(rootComponent); - rootComponent.TriggerRender(); - var authorizeViewComponentId = renderer.Batches.Single() - .GetComponentFrames().Single().ComponentId; - authorizationService.AuthorizeCalls.Clear(); - - // Act - rootComponent.AuthenticationState = CreateAuthenticationState("Ronaldo"); - rootComponent.TriggerRender(); - - // Assert: It's only one new diff. We skip the intermediate "await" render state - // because the task was completed synchronously. - Assert.Equal(2, renderer.Batches.Count); - var batch = renderer.Batches.Last(); - var diff = batch.DiffsByComponentId[authorizeViewComponentId].Single(); - Assert.Collection(diff.Edits, edit => - { - Assert.Equal(RenderTreeEditType.UpdateText, edit.Type); - AssertFrame.Text( - batch.ReferenceFrames[edit.ReferenceFrameIndex], - "You are authenticated as Ronaldo"); - }); - - // Assert: The IAuthorizationService was given expected criteria - Assert.Collection(authorizationService.AuthorizeCalls, call => - { - Assert.Equal("Ronaldo", call.user.Identity.Name); - Assert.Null(call.resource); - Assert.Collection(call.requirements, - req => Assert.IsType(req)); - }); - } - - [Fact] - public void ThrowsIfBothChildContentAndAuthorizedProvided() - { - // Arrange - var authorizationService = new TestAuthorizationService(); - var renderer = CreateTestRenderer(authorizationService); - var rootComponent = WrapInAuthorizeView( - authorized: context => builder => { }, - childContent: context => builder => { }); - - // Act/Assert - renderer.AssignRootComponentId(rootComponent); - var ex = Assert.Throws(() => - rootComponent.TriggerRender()); - Assert.Equal("Do not specify both 'Authorized' and 'ChildContent'.", ex.Message); - } - - [Fact] - public void RendersNothingUntilAuthorizationCompleted() - { - // Arrange - var @event = new ManualResetEventSlim(); - var authorizationService = new TestAuthorizationService(); - var renderer = CreateTestRenderer(authorizationService); - renderer.OnUpdateDisplayComplete = () => { @event.Set(); }; - var rootComponent = WrapInAuthorizeView( - notAuthorized: - context => builder => builder.AddContent(0, "You are not authorized")); - var authTcs = new TaskCompletionSource(); - rootComponent.AuthenticationState = authTcs.Task; - - // Act/Assert 1: Auth pending - renderer.AssignRootComponentId(rootComponent); - rootComponent.TriggerRender(); - var batch1 = renderer.Batches.Single(); - var authorizeViewComponentId = batch1.GetComponentFrames().Single().ComponentId; - var diff1 = batch1.DiffsByComponentId[authorizeViewComponentId].Single(); - Assert.Empty(diff1.Edits); - - // Act/Assert 2: Auth process completes asynchronously - @event.Reset(); - authTcs.SetResult(new AuthenticationState(new ClaimsPrincipal())); - - // We need to wait here because the continuations of SetResult will be scheduled to run asynchronously. - @event.Wait(Timeout); - - Assert.Equal(2, renderer.Batches.Count); - var batch2 = renderer.Batches[1]; - var diff2 = batch2.DiffsByComponentId[authorizeViewComponentId].Single(); - Assert.Collection(diff2.Edits, edit => - { - Assert.Equal(RenderTreeEditType.PrependFrame, edit.Type); - AssertFrame.Text( - batch2.ReferenceFrames[edit.ReferenceFrameIndex], - "You are not authorized"); - }); - } - - [Fact] - public void RendersAuthorizingUntilAuthorizationCompleted() - { - // Arrange - var @event = new ManualResetEventSlim(); - var authorizationService = new TestAuthorizationService(); - authorizationService.NextResult = AuthorizationResult.Success(); - var renderer = CreateTestRenderer(authorizationService); - renderer.OnUpdateDisplayComplete = () => { @event.Set(); }; - var rootComponent = WrapInAuthorizeView( - authorizing: builder => builder.AddContent(0, "Auth pending..."), - authorized: context => builder => builder.AddContent(0, $"Hello, {context.User.Identity.Name}!")); - var authTcs = new TaskCompletionSource(); - rootComponent.AuthenticationState = authTcs.Task; - - // Act/Assert 1: Auth pending - renderer.AssignRootComponentId(rootComponent); - rootComponent.TriggerRender(); - var batch1 = renderer.Batches.Single(); - var authorizeViewComponentId = batch1.GetComponentFrames().Single().ComponentId; - var diff1 = batch1.DiffsByComponentId[authorizeViewComponentId].Single(); - Assert.Collection(diff1.Edits, edit => - { - Assert.Equal(RenderTreeEditType.PrependFrame, edit.Type); - AssertFrame.Text( - batch1.ReferenceFrames[edit.ReferenceFrameIndex], - "Auth pending..."); - }); - - // Act/Assert 2: Auth process completes asynchronously - @event.Reset(); - authTcs.SetResult(CreateAuthenticationState("Monsieur").Result); - - // We need to wait here because the continuations of SetResult will be scheduled to run asynchronously. - @event.Wait(Timeout); - - Assert.Equal(2, renderer.Batches.Count); - var batch2 = renderer.Batches[1]; - var diff2 = batch2.DiffsByComponentId[authorizeViewComponentId].Single(); - Assert.Collection(diff2.Edits, edit => - { - Assert.Equal(RenderTreeEditType.UpdateText, edit.Type); - Assert.Equal(0, edit.SiblingIndex); - AssertFrame.Text( - batch2.ReferenceFrames[edit.ReferenceFrameIndex], - "Hello, Monsieur!"); - }); - - // Assert: The IAuthorizationService was given expected criteria - Assert.Collection(authorizationService.AuthorizeCalls, call => - { - Assert.Equal("Monsieur", call.user.Identity.Name); - Assert.Null(call.resource); - Assert.Collection(call.requirements, - req => Assert.IsType(req)); - }); - } - - [Fact] - public void IncludesPolicyInAuthorizeCall() - { - // Arrange - var authorizationService = new TestAuthorizationService(); - var renderer = CreateTestRenderer(authorizationService); - var rootComponent = WrapInAuthorizeView(policy: "MyTestPolicy"); - rootComponent.AuthenticationState = CreateAuthenticationState("Nellie"); - - // Act - renderer.AssignRootComponentId(rootComponent); - rootComponent.TriggerRender(); - - // Assert - Assert.Collection(authorizationService.AuthorizeCalls, call => - { - Assert.Equal("Nellie", call.user.Identity.Name); - Assert.Null(call.resource); - Assert.Collection(call.requirements, - req => Assert.Equal("MyTestPolicy", ((TestPolicyRequirement)req).PolicyName)); - }); - } - - [Fact] - public void IncludesRolesInAuthorizeCall() - { - // Arrange - var authorizationService = new TestAuthorizationService(); - var renderer = CreateTestRenderer(authorizationService); - var rootComponent = WrapInAuthorizeView(roles: "SuperTestRole1, SuperTestRole2"); - rootComponent.AuthenticationState = CreateAuthenticationState("Nellie"); - - // Act - renderer.AssignRootComponentId(rootComponent); - rootComponent.TriggerRender(); - - // Assert - Assert.Collection(authorizationService.AuthorizeCalls, call => - { - Assert.Equal("Nellie", call.user.Identity.Name); - Assert.Null(call.resource); - Assert.Collection(call.requirements, req => Assert.Equal( - new[] { "SuperTestRole1", "SuperTestRole2" }, - ((RolesAuthorizationRequirement)req).AllowedRoles)); - }); - } - - [Fact] - public void IncludesResourceInAuthorizeCall() - { - // Arrange - var authorizationService = new TestAuthorizationService(); - var renderer = CreateTestRenderer(authorizationService); - var resource = new object(); - var rootComponent = WrapInAuthorizeView(resource: resource); - rootComponent.AuthenticationState = CreateAuthenticationState("Nellie"); - - // Act - renderer.AssignRootComponentId(rootComponent); - rootComponent.TriggerRender(); - - // Assert - Assert.Collection(authorizationService.AuthorizeCalls, call => - { - Assert.Equal("Nellie", call.user.Identity.Name); - Assert.Same(resource, call.resource); - Assert.Collection(call.requirements, req => - Assert.IsType(req)); - }); - } - - [Fact] - public void RejectsNonemptyScheme() - { - // Arrange - var authorizationService = new TestAuthorizationService(); - var renderer = CreateTestRenderer(authorizationService); - var rootComponent = new TestAuthStateProviderComponent(builder => - { - builder.OpenComponent(0); - builder.CloseComponent(); - }); - renderer.AssignRootComponentId(rootComponent); - - // Act/Assert - var ex = Assert.Throws(rootComponent.TriggerRender); - Assert.Equal("The authorization data specifies an authentication scheme with value 'test scheme'. Authentication schemes cannot be specified for components.", ex.Message); - } - - private static TestAuthStateProviderComponent WrapInAuthorizeView( - RenderFragment childContent = null, - RenderFragment authorized = null, - RenderFragment notAuthorized = null, - RenderFragment authorizing = null, - string policy = null, - string roles = null, - object resource = null) - { - return new TestAuthStateProviderComponent(builder => - { - builder.OpenComponent(0); - builder.AddAttribute(1, nameof(AuthorizeView.ChildContent), childContent); - builder.AddAttribute(2, nameof(AuthorizeView.Authorized), authorized); - builder.AddAttribute(3, nameof(AuthorizeView.NotAuthorized), notAuthorized); - builder.AddAttribute(4, nameof(AuthorizeView.Authorizing), authorizing); - builder.AddAttribute(5, nameof(AuthorizeView.Policy), policy); - builder.AddAttribute(6, nameof(AuthorizeView.Roles), roles); - builder.AddAttribute(7, nameof(AuthorizeView.Resource), resource); - builder.CloseComponent(); - }); - } - - class TestAuthStateProviderComponent : AutoRenderComponent - { - private readonly RenderFragment _childContent; - - public Task AuthenticationState { get; set; } - = Task.FromResult(new AuthenticationState(new ClaimsPrincipal())); - - public TestAuthStateProviderComponent(RenderFragment childContent) - { - _childContent = childContent; - } - - protected override void BuildRenderTree(RenderTreeBuilder builder) - { - builder.OpenComponent>>(0); - builder.AddAttribute(1, nameof(CascadingValue>.Value), AuthenticationState); - builder.AddAttribute(2, "ChildContent", (RenderFragment)(builder => - { - builder.OpenComponent(0); - builder.AddAttribute(1, "ChildContent", _childContent); - builder.CloseComponent(); - })); - builder.CloseComponent(); - } - } - - // This is useful to show that the reason why a CascadingValue refreshes is because the - // value itself changed, not just that we're re-rendering the entire tree and have to - // recurse into all descendants because we're passing ChildContent - class NeverReRenderComponent : ComponentBase - { - [Parameter] public RenderFragment ChildContent { get; set; } - - protected override bool ShouldRender() => false; - - protected override void BuildRenderTree(RenderTreeBuilder builder) - { - builder.AddContent(0, ChildContent); - } - } - - public static Task CreateAuthenticationState(string username) - => Task.FromResult(new AuthenticationState( - new ClaimsPrincipal(new TestIdentity { Name = username }))); - - public TestRenderer CreateTestRenderer(IAuthorizationService authorizationService) - { - var serviceCollection = new ServiceCollection(); - serviceCollection.AddSingleton(authorizationService); - serviceCollection.AddSingleton(new TestAuthorizationPolicyProvider()); - return new TestRenderer(serviceCollection.BuildServiceProvider()); - } - - public class AuthorizeViewCoreWithScheme : AuthorizeViewCore - { - protected override IAuthorizeData[] GetAuthorizeData() - => new[] { new AuthorizeAttribute { AuthenticationSchemes = "test scheme" } }; - } - } -} diff --git a/src/Components/Authorization/test/CascadingAuthenticationStateTest.cs b/src/Components/Authorization/test/CascadingAuthenticationStateTest.cs deleted file mode 100644 index ab942fe82a..0000000000 --- a/src/Components/Authorization/test/CascadingAuthenticationStateTest.cs +++ /dev/null @@ -1,207 +0,0 @@ -// 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.Linq; -using System.Security.Claims; -using System.Security.Principal; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Components.Rendering; -using Microsoft.AspNetCore.Components.RenderTree; -using Microsoft.AspNetCore.Components.Test.Helpers; -using Microsoft.Extensions.DependencyInjection; -using Xunit; - -namespace Microsoft.AspNetCore.Components.Authorization -{ - public class CascadingAuthenticationStateTest - { - [Fact] - public void RequiresRegisteredService() - { - // Arrange - var renderer = new TestRenderer(); - var component = new AutoRenderFragmentComponent(builder => - { - builder.OpenComponent(0); - builder.CloseComponent(); - }); - - // Act/Assert - renderer.AssignRootComponentId(component); - var ex = Assert.Throws(() => component.TriggerRender()); - Assert.Contains($"There is no registered service of type '{typeof(AuthenticationStateProvider).FullName}'.", ex.Message); - } - - [Fact] - public void SuppliesSynchronouslyAvailableAuthStateToChildContent() - { - // Arrange: Service - var services = new ServiceCollection(); - var authStateProvider = new TestAuthenticationStateProvider() - { - CurrentAuthStateTask = Task.FromResult(CreateAuthenticationState("Bert")) - }; - services.AddSingleton(authStateProvider); - - // Arrange: Renderer and component - var renderer = new TestRenderer(services.BuildServiceProvider()); - var component = new UseCascadingAuthenticationStateComponent(); - - // Act - renderer.AssignRootComponentId(component); - component.TriggerRender(); - - // Assert - var batch = renderer.Batches.Single(); - var receiveAuthStateId = batch.GetComponentFrames().Single().ComponentId; - var receiveAuthStateDiff = batch.DiffsByComponentId[receiveAuthStateId].Single(); - Assert.Collection(receiveAuthStateDiff.Edits, edit => - { - Assert.Equal(RenderTreeEditType.PrependFrame, edit.Type); - AssertFrame.Text( - batch.ReferenceFrames[edit.ReferenceFrameIndex], - "Authenticated: True; Name: Bert; Pending: False; Renders: 1"); - }); - } - - [Fact] - public void SuppliesAsynchronouslyAvailableAuthStateToChildContent() - { - // Arrange: Service - var services = new ServiceCollection(); - var authStateTaskCompletionSource = new TaskCompletionSource(); - var authStateProvider = new TestAuthenticationStateProvider() - { - CurrentAuthStateTask = authStateTaskCompletionSource.Task - }; - services.AddSingleton(authStateProvider); - - // Arrange: Renderer and component - var renderer = new TestRenderer(services.BuildServiceProvider()); - var component = new UseCascadingAuthenticationStateComponent(); - - // Act 1: Initial synchronous render - renderer.AssignRootComponentId(component); - component.TriggerRender(); - - // Assert 1: Empty state - var batch1 = renderer.Batches.Single(); - var receiveAuthStateFrame = batch1.GetComponentFrames().Single(); - var receiveAuthStateId = receiveAuthStateFrame.ComponentId; - var receiveAuthStateComponent = (ReceiveAuthStateComponent)receiveAuthStateFrame.Component; - var receiveAuthStateDiff1 = batch1.DiffsByComponentId[receiveAuthStateId].Single(); - Assert.Collection(receiveAuthStateDiff1.Edits, edit => - { - Assert.Equal(RenderTreeEditType.PrependFrame, edit.Type); - AssertFrame.Text( - batch1.ReferenceFrames[edit.ReferenceFrameIndex], - "Authenticated: False; Name: ; Pending: True; Renders: 1"); - }); - - // Act/Assert 2: Auth state fetch task completes in background - // No new renders yet, because the cascading parameter itself hasn't changed - authStateTaskCompletionSource.SetResult(CreateAuthenticationState("Bert")); - Assert.Single(renderer.Batches); - - // Act/Assert 3: Refresh display - receiveAuthStateComponent.TriggerRender(); - Assert.Equal(2, renderer.Batches.Count); - var batch2 = renderer.Batches.Last(); - var receiveAuthStateDiff2 = batch2.DiffsByComponentId[receiveAuthStateId].Single(); - Assert.Collection(receiveAuthStateDiff2.Edits, edit => - { - Assert.Equal(RenderTreeEditType.UpdateText, edit.Type); - AssertFrame.Text( - batch2.ReferenceFrames[edit.ReferenceFrameIndex], - "Authenticated: True; Name: Bert; Pending: False; Renders: 2"); - }); - } - - [Fact] - public void RespondsToNotificationsFromAuthenticationStateProvider() - { - // Arrange: Service - var services = new ServiceCollection(); - var authStateProvider = new TestAuthenticationStateProvider() - { - CurrentAuthStateTask = Task.FromResult(CreateAuthenticationState(null)) - }; - services.AddSingleton(authStateProvider); - - // Arrange: Renderer and component, initially rendered - var renderer = new TestRenderer(services.BuildServiceProvider()); - var component = new UseCascadingAuthenticationStateComponent(); - renderer.AssignRootComponentId(component); - component.TriggerRender(); - var receiveAuthStateId = renderer.Batches.Single() - .GetComponentFrames().Single().ComponentId; - - // Act 2: AuthenticationStateProvider issues notification - authStateProvider.TriggerAuthenticationStateChanged( - Task.FromResult(CreateAuthenticationState("Bert"))); - - // Assert 2: Re-renders content - Assert.Equal(2, renderer.Batches.Count); - var batch = renderer.Batches.Last(); - var receiveAuthStateDiff = batch.DiffsByComponentId[receiveAuthStateId].Single(); - Assert.Collection(receiveAuthStateDiff.Edits, edit => - { - Assert.Equal(RenderTreeEditType.UpdateText, edit.Type); - AssertFrame.Text( - batch.ReferenceFrames[edit.ReferenceFrameIndex], - "Authenticated: True; Name: Bert; Pending: False; Renders: 2"); - }); - } - - class ReceiveAuthStateComponent : AutoRenderComponent - { - int numRenders; - - [CascadingParameter] Task AuthStateTask { get; set; } - - protected override void BuildRenderTree(RenderTreeBuilder builder) - { - numRenders++; - - if (AuthStateTask.IsCompleted) - { - var identity = AuthStateTask.Result.User.Identity; - builder.AddContent(0, $"Authenticated: {identity.IsAuthenticated}; Name: {identity.Name}; Pending: False; Renders: {numRenders}"); - } - else - { - builder.AddContent(0, $"Authenticated: False; Name: ; Pending: True; Renders: {numRenders}"); - } - } - } - - class UseCascadingAuthenticationStateComponent : AutoRenderComponent - { - protected override void BuildRenderTree(RenderTreeBuilder builder) - { - builder.OpenComponent(0); - builder.AddAttribute(1, "ChildContent", new RenderFragment(childBuilder => - { - childBuilder.OpenComponent(0); - childBuilder.CloseComponent(); - })); - builder.CloseComponent(); - } - } - - public static AuthenticationState CreateAuthenticationState(string username) - => new AuthenticationState(new ClaimsPrincipal(username == null - ? new ClaimsIdentity() - : (IIdentity)new TestIdentity { Name = username })); - - class TestIdentity : IIdentity - { - public string AuthenticationType => "Test"; - - public bool IsAuthenticated => true; - - public string Name { get; set; } - } - } -} diff --git a/src/Components/Authorization/test/Microsoft.AspNetCore.Components.Authorization.Tests.csproj b/src/Components/Authorization/test/Microsoft.AspNetCore.Components.Authorization.Tests.csproj deleted file mode 100644 index 5f7ae8f772..0000000000 --- a/src/Components/Authorization/test/Microsoft.AspNetCore.Components.Authorization.Tests.csproj +++ /dev/null @@ -1,18 +0,0 @@ - - - - $(DefaultNetCoreTargetFramework) - Microsoft.AspNetCore.Components.Authorization - - - - - - - - - - - - - diff --git a/src/Components/Authorization/test/TestAuthenticationStateProvider.cs b/src/Components/Authorization/test/TestAuthenticationStateProvider.cs deleted file mode 100644 index 3e8faf6a50..0000000000 --- a/src/Components/Authorization/test/TestAuthenticationStateProvider.cs +++ /dev/null @@ -1,22 +0,0 @@ -// 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.Threading.Tasks; - -namespace Microsoft.AspNetCore.Components.Authorization -{ - public class TestAuthenticationStateProvider : AuthenticationStateProvider - { - public Task CurrentAuthStateTask { get; set; } - - public override Task GetAuthenticationStateAsync() - { - return CurrentAuthStateTask; - } - - internal void TriggerAuthenticationStateChanged(Task authState) - { - NotifyAuthenticationStateChanged(authState); - } - } -} diff --git a/src/Components/Authorization/test/TestAuthorizationPolicyProvider.cs b/src/Components/Authorization/test/TestAuthorizationPolicyProvider.cs deleted file mode 100644 index 7935f77138..0000000000 --- a/src/Components/Authorization/test/TestAuthorizationPolicyProvider.cs +++ /dev/null @@ -1,31 +0,0 @@ -// 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.Threading.Tasks; -using Microsoft.AspNetCore.Authorization; - -namespace Microsoft.AspNetCore.Components.Authorization -{ - public class TestAuthorizationPolicyProvider : IAuthorizationPolicyProvider - { - private readonly AuthorizationOptions options = new AuthorizationOptions(); - - public Task GetDefaultPolicyAsync() - => Task.FromResult(options.DefaultPolicy); - - public Task GetFallbackPolicyAsync() - => Task.FromResult(options.FallbackPolicy); - - public Task GetPolicyAsync(string policyName) => Task.FromResult( - new AuthorizationPolicy(new[] - { - new TestPolicyRequirement { PolicyName = policyName } - }, - new[] { $"TestScheme:{policyName}" })); - } - - public class TestPolicyRequirement : IAuthorizationRequirement - { - public string PolicyName { get; set; } - } -} diff --git a/src/Components/Authorization/test/TestAuthorizationService.cs b/src/Components/Authorization/test/TestAuthorizationService.cs deleted file mode 100644 index 42f2d4b936..0000000000 --- a/src/Components/Authorization/test/TestAuthorizationService.cs +++ /dev/null @@ -1,34 +0,0 @@ -// 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.Collections.Generic; -using System.Security.Claims; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Authorization; - -namespace Microsoft.AspNetCore.Components.Authorization -{ - public class TestAuthorizationService : IAuthorizationService - { - public AuthorizationResult NextResult { get; set; } - = AuthorizationResult.Failed(); - - public List<(ClaimsPrincipal user, object resource, IEnumerable requirements)> AuthorizeCalls { get; } - = new List<(ClaimsPrincipal user, object resource, IEnumerable requirements)>(); - - public Task AuthorizeAsync(ClaimsPrincipal user, object resource, IEnumerable requirements) - { - AuthorizeCalls.Add((user, resource, requirements)); - - // The TestAuthorizationService doesn't actually apply any authorization requirements - // It just returns the specified NextResult, since we're not trying to test the logic - // in DefaultAuthorizationService or similar here. So it's up to tests to set a desired - // NextResult and assert that the expected criteria were passed by inspecting AuthorizeCalls. - return Task.FromResult(NextResult); - } - - public Task AuthorizeAsync(ClaimsPrincipal user, object resource, string policyName) - => throw new NotImplementedException(); - } -} diff --git a/src/Components/Authorization/test/TestIdentity.cs b/src/Components/Authorization/test/TestIdentity.cs deleted file mode 100644 index 936c6ee0ea..0000000000 --- a/src/Components/Authorization/test/TestIdentity.cs +++ /dev/null @@ -1,16 +0,0 @@ -// 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.Security.Principal; - -namespace Microsoft.AspNetCore.Components.Authorization -{ - public class TestIdentity : IIdentity - { - public string AuthenticationType => "Test"; - - public bool IsAuthenticated => true; - - public string Name { get; set; } - } -} diff --git a/src/Components/Blazor.sln b/src/Components/Blazor.sln new file mode 100644 index 0000000000..882b8eb507 --- /dev/null +++ b/src/Components/Blazor.sln @@ -0,0 +1,484 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29728.190 +MinimumVisualStudioVersion = 15.0.26124.0 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "benchmarkapps", "benchmarkapps", "{46E744CC-D332-401F-B074-A40341F0F832}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Wasm.Performance", "Wasm.Performance", "{9B360D1A-5355-4942-B77E-76A1AC67911B}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Wasm.Performance.Driver", "benchmarkapps\Wasm.Performance\Driver\Wasm.Performance.Driver.csproj", "{85E2777A-F8E0-48B8-9FC4-B60FDC7B45B7}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Wasm.Performance.TestApp", "benchmarkapps\Wasm.Performance\TestApp\Wasm.Performance.TestApp.csproj", "{10E5AD2E-25A9-4B8B-BD33-207B12D5BAE4}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Blazor", "Blazor", "{B29FB58D-FAE5-405E-9695-BCF93582BE9A}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Blazor", "Blazor", "{E363191C-6C15-4C40-8698-B0AD5AA09700}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Blazor", "Blazor\Blazor\src\Microsoft.AspNetCore.Blazor.csproj", "{8A585A38-917D-4A7E-8AFD-E860C76878FA}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Blazor.Tests", "Blazor\Blazor\test\Microsoft.AspNetCore.Blazor.Tests.csproj", "{75DA4341-5B7F-419C-8EED-3492013D8EB5}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{A82B9830-447D-4E26-BEB7-C724A3956C0D}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Blazor.Build", "Blazor\Build\src\Microsoft.AspNetCore.Blazor.Build.csproj", "{201D53B3-2D33-40AD-813F-347A0C1998ED}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Blazor.Build.Tests", "Blazor\Build\test\Microsoft.AspNetCore.Blazor.Build.Tests.csproj", "{AB13059F-8F21-48F6-B9F3-EAF260D9CB81}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "testassets", "testassets", "{B4ACD900-27B6-482B-B434-2C1E86E9D8BC}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "blazorhosted", "Blazor\Build\testassets\blazorhosted\blazorhosted.csproj", "{5F44DC59-3B4E-4E87-973F-C9FB4BBFD03D}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "classlibrarywithsatelliteassemblies", "Blazor\Build\testassets\classlibrarywithsatelliteassemblies\classlibrarywithsatelliteassemblies.csproj", "{4BD2D530-83C7-4A86-AF8E-FE1FECBF64C6}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RazorClassLibrary", "Blazor\Build\testassets\razorclasslibrary\RazorClassLibrary.csproj", "{779749F3-8D4F-42BD-9219-37502AD68F0E}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "standalone", "Blazor\Build\testassets\standalone\standalone.csproj", "{9C41BA92-FBC8-4E11-9A71-0B07906A2D6C}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DevServer", "DevServer", "{A44FB7D1-78AB-41C4-B1C7-94399396EA6C}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Blazor.DevServer", "Blazor\DevServer\src\Microsoft.AspNetCore.Blazor.DevServer.csproj", "{0ED336B7-6FAB-4872-8D75-1CDD5A5DDBB2}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Http", "Http", "{F4995C96-8D4E-4B26-8FB8-614B020156C2}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Blazor.HttpClient", "Blazor\Http\src\Microsoft.AspNetCore.Blazor.HttpClient.csproj", "{FAFE3FF2-D36D-47DA-833D-C382A902705E}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Blazor.HttpClient.Tests", "Blazor\Http\test\Microsoft.AspNetCore.Blazor.HttpClient.Tests.csproj", "{2C10DF3B-D138-414A-BB36-02E45A7B6025}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Mono.WebAssembly.Interop", "Mono.WebAssembly.Interop", "{37FA056D-A7B3-4F72-A8B9-8D3C175E831E}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mono.WebAssembly.Interop", "Blazor\Mono.WebAssembly.Interop\src\Mono.WebAssembly.Interop.csproj", "{FBD7C733-200E-4BED-8B31-2610C2263F72}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Server", "Server", "{7920B09F-8016-49CF-A229-E72D0CECDD17}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Blazor.Server", "Blazor\Server\src\Microsoft.AspNetCore.Blazor.Server.csproj", "{BDBEDE12-74C1-466E-B8AE-49EC40F83866}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "testassets", "testassets", "{CBD2BB24-3EC3-4950-ABE4-8C521D258DCD}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HostedInAspNet.Client", "Blazor\testassets\HostedInAspNet.Client\HostedInAspNet.Client.csproj", "{8276993E-3F54-4D2F-8DDA-E86F2C6BEF1E}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HostedInAspNet.Server", "Blazor\testassets\HostedInAspNet.Server\HostedInAspNet.Server.csproj", "{CFA20A59-F52B-47A2-BD5D-B600D9576BDA}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MonoSanity", "Blazor\testassets\MonoSanity\MonoSanity.csproj", "{C97721BB-8D89-4167-9E59-839C237BA270}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MonoSanityClient", "Blazor\testassets\MonoSanityClient\MonoSanityClient.csproj", "{7F357E7B-BF33-4055-9A21-37B3507BFF90}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StandaloneApp", "Blazor\testassets\StandaloneApp\StandaloneApp.csproj", "{236FC110-FBE0-476D-ADC5-D98E23BAA1EE}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Validation", "Validation", "{09758C93-6707-46E3-9211-470449280C2C}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Blazor.DataAnnotations.Validation", "Blazor\Validation\src\Microsoft.AspNetCore.Blazor.DataAnnotations.Validation.csproj", "{52F0CF32-9506-4D9C-B715-52900B219BDF}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Blazor.DataAnnotations.Validation.Tests", "Blazor\Validation\test\Microsoft.AspNetCore.Blazor.DataAnnotations.Validation.Tests.csproj", "{C1CC2480-7925-4391-86F5-60653D864E87}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{194596E0-E6F5-4728-8A7A-A82EA0893111}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Components.E2ETests", "test\E2ETest\Microsoft.AspNetCore.Components.E2ETests.csproj", "{2DD2A221-255E-4A57-A2C3-B24C9BDC2E24}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "testassets", "testassets", "{10C06583-8506-42DE-863E-EAD48A1F7579}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BasicTestApp", "test\testassets\BasicTestApp\BasicTestApp.csproj", "{376D8A5F-923C-4AF9-8627-EA0E8E54AEDF}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ComponentsApp.App", "test\testassets\ComponentsApp.App\ComponentsApp.App.csproj", "{1B633436-B999-467F-8A8F-778BB075CD35}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ComponentsApp.Server", "test\testassets\ComponentsApp.Server\ComponentsApp.Server.csproj", "{DA17FB91-EF6F-4C34-A5D4-1A0F7E42D699}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestContentPackage", "test\testassets\TestContentPackage\TestContentPackage.csproj", "{BC3DDF14-4961-49AB-8F19-2A23F535B0DE}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Components.TestServer", "test\testassets\TestServer\Components.TestServer.csproj", "{EACC194A-8C1B-424D-B8FE-330E14CAF525}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {85E2777A-F8E0-48B8-9FC4-B60FDC7B45B7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {85E2777A-F8E0-48B8-9FC4-B60FDC7B45B7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {85E2777A-F8E0-48B8-9FC4-B60FDC7B45B7}.Debug|x64.ActiveCfg = Debug|Any CPU + {85E2777A-F8E0-48B8-9FC4-B60FDC7B45B7}.Debug|x64.Build.0 = Debug|Any CPU + {85E2777A-F8E0-48B8-9FC4-B60FDC7B45B7}.Debug|x86.ActiveCfg = Debug|Any CPU + {85E2777A-F8E0-48B8-9FC4-B60FDC7B45B7}.Debug|x86.Build.0 = Debug|Any CPU + {85E2777A-F8E0-48B8-9FC4-B60FDC7B45B7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {85E2777A-F8E0-48B8-9FC4-B60FDC7B45B7}.Release|Any CPU.Build.0 = Release|Any CPU + {85E2777A-F8E0-48B8-9FC4-B60FDC7B45B7}.Release|x64.ActiveCfg = Release|Any CPU + {85E2777A-F8E0-48B8-9FC4-B60FDC7B45B7}.Release|x64.Build.0 = Release|Any CPU + {85E2777A-F8E0-48B8-9FC4-B60FDC7B45B7}.Release|x86.ActiveCfg = Release|Any CPU + {85E2777A-F8E0-48B8-9FC4-B60FDC7B45B7}.Release|x86.Build.0 = Release|Any CPU + {10E5AD2E-25A9-4B8B-BD33-207B12D5BAE4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {10E5AD2E-25A9-4B8B-BD33-207B12D5BAE4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {10E5AD2E-25A9-4B8B-BD33-207B12D5BAE4}.Debug|x64.ActiveCfg = Debug|Any CPU + {10E5AD2E-25A9-4B8B-BD33-207B12D5BAE4}.Debug|x64.Build.0 = Debug|Any CPU + {10E5AD2E-25A9-4B8B-BD33-207B12D5BAE4}.Debug|x86.ActiveCfg = Debug|Any CPU + {10E5AD2E-25A9-4B8B-BD33-207B12D5BAE4}.Debug|x86.Build.0 = Debug|Any CPU + {10E5AD2E-25A9-4B8B-BD33-207B12D5BAE4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {10E5AD2E-25A9-4B8B-BD33-207B12D5BAE4}.Release|Any CPU.Build.0 = Release|Any CPU + {10E5AD2E-25A9-4B8B-BD33-207B12D5BAE4}.Release|x64.ActiveCfg = Release|Any CPU + {10E5AD2E-25A9-4B8B-BD33-207B12D5BAE4}.Release|x64.Build.0 = Release|Any CPU + {10E5AD2E-25A9-4B8B-BD33-207B12D5BAE4}.Release|x86.ActiveCfg = Release|Any CPU + {10E5AD2E-25A9-4B8B-BD33-207B12D5BAE4}.Release|x86.Build.0 = Release|Any CPU + {8A585A38-917D-4A7E-8AFD-E860C76878FA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8A585A38-917D-4A7E-8AFD-E860C76878FA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8A585A38-917D-4A7E-8AFD-E860C76878FA}.Debug|x64.ActiveCfg = Debug|Any CPU + {8A585A38-917D-4A7E-8AFD-E860C76878FA}.Debug|x64.Build.0 = Debug|Any CPU + {8A585A38-917D-4A7E-8AFD-E860C76878FA}.Debug|x86.ActiveCfg = Debug|Any CPU + {8A585A38-917D-4A7E-8AFD-E860C76878FA}.Debug|x86.Build.0 = Debug|Any CPU + {8A585A38-917D-4A7E-8AFD-E860C76878FA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8A585A38-917D-4A7E-8AFD-E860C76878FA}.Release|Any CPU.Build.0 = Release|Any CPU + {8A585A38-917D-4A7E-8AFD-E860C76878FA}.Release|x64.ActiveCfg = Release|Any CPU + {8A585A38-917D-4A7E-8AFD-E860C76878FA}.Release|x64.Build.0 = Release|Any CPU + {8A585A38-917D-4A7E-8AFD-E860C76878FA}.Release|x86.ActiveCfg = Release|Any CPU + {8A585A38-917D-4A7E-8AFD-E860C76878FA}.Release|x86.Build.0 = Release|Any CPU + {75DA4341-5B7F-419C-8EED-3492013D8EB5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {75DA4341-5B7F-419C-8EED-3492013D8EB5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {75DA4341-5B7F-419C-8EED-3492013D8EB5}.Debug|x64.ActiveCfg = Debug|Any CPU + {75DA4341-5B7F-419C-8EED-3492013D8EB5}.Debug|x64.Build.0 = Debug|Any CPU + {75DA4341-5B7F-419C-8EED-3492013D8EB5}.Debug|x86.ActiveCfg = Debug|Any CPU + {75DA4341-5B7F-419C-8EED-3492013D8EB5}.Debug|x86.Build.0 = Debug|Any CPU + {75DA4341-5B7F-419C-8EED-3492013D8EB5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {75DA4341-5B7F-419C-8EED-3492013D8EB5}.Release|Any CPU.Build.0 = Release|Any CPU + {75DA4341-5B7F-419C-8EED-3492013D8EB5}.Release|x64.ActiveCfg = Release|Any CPU + {75DA4341-5B7F-419C-8EED-3492013D8EB5}.Release|x64.Build.0 = Release|Any CPU + {75DA4341-5B7F-419C-8EED-3492013D8EB5}.Release|x86.ActiveCfg = Release|Any CPU + {75DA4341-5B7F-419C-8EED-3492013D8EB5}.Release|x86.Build.0 = Release|Any CPU + {201D53B3-2D33-40AD-813F-347A0C1998ED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {201D53B3-2D33-40AD-813F-347A0C1998ED}.Debug|Any CPU.Build.0 = Debug|Any CPU + {201D53B3-2D33-40AD-813F-347A0C1998ED}.Debug|x64.ActiveCfg = Debug|Any CPU + {201D53B3-2D33-40AD-813F-347A0C1998ED}.Debug|x64.Build.0 = Debug|Any CPU + {201D53B3-2D33-40AD-813F-347A0C1998ED}.Debug|x86.ActiveCfg = Debug|Any CPU + {201D53B3-2D33-40AD-813F-347A0C1998ED}.Debug|x86.Build.0 = Debug|Any CPU + {201D53B3-2D33-40AD-813F-347A0C1998ED}.Release|Any CPU.ActiveCfg = Release|Any CPU + {201D53B3-2D33-40AD-813F-347A0C1998ED}.Release|Any CPU.Build.0 = Release|Any CPU + {201D53B3-2D33-40AD-813F-347A0C1998ED}.Release|x64.ActiveCfg = Release|Any CPU + {201D53B3-2D33-40AD-813F-347A0C1998ED}.Release|x64.Build.0 = Release|Any CPU + {201D53B3-2D33-40AD-813F-347A0C1998ED}.Release|x86.ActiveCfg = Release|Any CPU + {201D53B3-2D33-40AD-813F-347A0C1998ED}.Release|x86.Build.0 = Release|Any CPU + {AB13059F-8F21-48F6-B9F3-EAF260D9CB81}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AB13059F-8F21-48F6-B9F3-EAF260D9CB81}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AB13059F-8F21-48F6-B9F3-EAF260D9CB81}.Debug|x64.ActiveCfg = Debug|Any CPU + {AB13059F-8F21-48F6-B9F3-EAF260D9CB81}.Debug|x64.Build.0 = Debug|Any CPU + {AB13059F-8F21-48F6-B9F3-EAF260D9CB81}.Debug|x86.ActiveCfg = Debug|Any CPU + {AB13059F-8F21-48F6-B9F3-EAF260D9CB81}.Debug|x86.Build.0 = Debug|Any CPU + {AB13059F-8F21-48F6-B9F3-EAF260D9CB81}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AB13059F-8F21-48F6-B9F3-EAF260D9CB81}.Release|Any CPU.Build.0 = Release|Any CPU + {AB13059F-8F21-48F6-B9F3-EAF260D9CB81}.Release|x64.ActiveCfg = Release|Any CPU + {AB13059F-8F21-48F6-B9F3-EAF260D9CB81}.Release|x64.Build.0 = Release|Any CPU + {AB13059F-8F21-48F6-B9F3-EAF260D9CB81}.Release|x86.ActiveCfg = Release|Any CPU + {AB13059F-8F21-48F6-B9F3-EAF260D9CB81}.Release|x86.Build.0 = Release|Any CPU + {5F44DC59-3B4E-4E87-973F-C9FB4BBFD03D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5F44DC59-3B4E-4E87-973F-C9FB4BBFD03D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5F44DC59-3B4E-4E87-973F-C9FB4BBFD03D}.Debug|x64.ActiveCfg = Debug|Any CPU + {5F44DC59-3B4E-4E87-973F-C9FB4BBFD03D}.Debug|x64.Build.0 = Debug|Any CPU + {5F44DC59-3B4E-4E87-973F-C9FB4BBFD03D}.Debug|x86.ActiveCfg = Debug|Any CPU + {5F44DC59-3B4E-4E87-973F-C9FB4BBFD03D}.Debug|x86.Build.0 = Debug|Any CPU + {5F44DC59-3B4E-4E87-973F-C9FB4BBFD03D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5F44DC59-3B4E-4E87-973F-C9FB4BBFD03D}.Release|Any CPU.Build.0 = Release|Any CPU + {5F44DC59-3B4E-4E87-973F-C9FB4BBFD03D}.Release|x64.ActiveCfg = Release|Any CPU + {5F44DC59-3B4E-4E87-973F-C9FB4BBFD03D}.Release|x64.Build.0 = Release|Any CPU + {5F44DC59-3B4E-4E87-973F-C9FB4BBFD03D}.Release|x86.ActiveCfg = Release|Any CPU + {5F44DC59-3B4E-4E87-973F-C9FB4BBFD03D}.Release|x86.Build.0 = Release|Any CPU + {4BD2D530-83C7-4A86-AF8E-FE1FECBF64C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4BD2D530-83C7-4A86-AF8E-FE1FECBF64C6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4BD2D530-83C7-4A86-AF8E-FE1FECBF64C6}.Debug|x64.ActiveCfg = Debug|Any CPU + {4BD2D530-83C7-4A86-AF8E-FE1FECBF64C6}.Debug|x64.Build.0 = Debug|Any CPU + {4BD2D530-83C7-4A86-AF8E-FE1FECBF64C6}.Debug|x86.ActiveCfg = Debug|Any CPU + {4BD2D530-83C7-4A86-AF8E-FE1FECBF64C6}.Debug|x86.Build.0 = Debug|Any CPU + {4BD2D530-83C7-4A86-AF8E-FE1FECBF64C6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4BD2D530-83C7-4A86-AF8E-FE1FECBF64C6}.Release|Any CPU.Build.0 = Release|Any CPU + {4BD2D530-83C7-4A86-AF8E-FE1FECBF64C6}.Release|x64.ActiveCfg = Release|Any CPU + {4BD2D530-83C7-4A86-AF8E-FE1FECBF64C6}.Release|x64.Build.0 = Release|Any CPU + {4BD2D530-83C7-4A86-AF8E-FE1FECBF64C6}.Release|x86.ActiveCfg = Release|Any CPU + {4BD2D530-83C7-4A86-AF8E-FE1FECBF64C6}.Release|x86.Build.0 = Release|Any CPU + {779749F3-8D4F-42BD-9219-37502AD68F0E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {779749F3-8D4F-42BD-9219-37502AD68F0E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {779749F3-8D4F-42BD-9219-37502AD68F0E}.Debug|x64.ActiveCfg = Debug|Any CPU + {779749F3-8D4F-42BD-9219-37502AD68F0E}.Debug|x64.Build.0 = Debug|Any CPU + {779749F3-8D4F-42BD-9219-37502AD68F0E}.Debug|x86.ActiveCfg = Debug|Any CPU + {779749F3-8D4F-42BD-9219-37502AD68F0E}.Debug|x86.Build.0 = Debug|Any CPU + {779749F3-8D4F-42BD-9219-37502AD68F0E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {779749F3-8D4F-42BD-9219-37502AD68F0E}.Release|Any CPU.Build.0 = Release|Any CPU + {779749F3-8D4F-42BD-9219-37502AD68F0E}.Release|x64.ActiveCfg = Release|Any CPU + {779749F3-8D4F-42BD-9219-37502AD68F0E}.Release|x64.Build.0 = Release|Any CPU + {779749F3-8D4F-42BD-9219-37502AD68F0E}.Release|x86.ActiveCfg = Release|Any CPU + {779749F3-8D4F-42BD-9219-37502AD68F0E}.Release|x86.Build.0 = Release|Any CPU + {9C41BA92-FBC8-4E11-9A71-0B07906A2D6C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9C41BA92-FBC8-4E11-9A71-0B07906A2D6C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9C41BA92-FBC8-4E11-9A71-0B07906A2D6C}.Debug|x64.ActiveCfg = Debug|Any CPU + {9C41BA92-FBC8-4E11-9A71-0B07906A2D6C}.Debug|x64.Build.0 = Debug|Any CPU + {9C41BA92-FBC8-4E11-9A71-0B07906A2D6C}.Debug|x86.ActiveCfg = Debug|Any CPU + {9C41BA92-FBC8-4E11-9A71-0B07906A2D6C}.Debug|x86.Build.0 = Debug|Any CPU + {9C41BA92-FBC8-4E11-9A71-0B07906A2D6C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9C41BA92-FBC8-4E11-9A71-0B07906A2D6C}.Release|Any CPU.Build.0 = Release|Any CPU + {9C41BA92-FBC8-4E11-9A71-0B07906A2D6C}.Release|x64.ActiveCfg = Release|Any CPU + {9C41BA92-FBC8-4E11-9A71-0B07906A2D6C}.Release|x64.Build.0 = Release|Any CPU + {9C41BA92-FBC8-4E11-9A71-0B07906A2D6C}.Release|x86.ActiveCfg = Release|Any CPU + {9C41BA92-FBC8-4E11-9A71-0B07906A2D6C}.Release|x86.Build.0 = Release|Any CPU + {0ED336B7-6FAB-4872-8D75-1CDD5A5DDBB2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0ED336B7-6FAB-4872-8D75-1CDD5A5DDBB2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0ED336B7-6FAB-4872-8D75-1CDD5A5DDBB2}.Debug|x64.ActiveCfg = Debug|Any CPU + {0ED336B7-6FAB-4872-8D75-1CDD5A5DDBB2}.Debug|x64.Build.0 = Debug|Any CPU + {0ED336B7-6FAB-4872-8D75-1CDD5A5DDBB2}.Debug|x86.ActiveCfg = Debug|Any CPU + {0ED336B7-6FAB-4872-8D75-1CDD5A5DDBB2}.Debug|x86.Build.0 = Debug|Any CPU + {0ED336B7-6FAB-4872-8D75-1CDD5A5DDBB2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0ED336B7-6FAB-4872-8D75-1CDD5A5DDBB2}.Release|Any CPU.Build.0 = Release|Any CPU + {0ED336B7-6FAB-4872-8D75-1CDD5A5DDBB2}.Release|x64.ActiveCfg = Release|Any CPU + {0ED336B7-6FAB-4872-8D75-1CDD5A5DDBB2}.Release|x64.Build.0 = Release|Any CPU + {0ED336B7-6FAB-4872-8D75-1CDD5A5DDBB2}.Release|x86.ActiveCfg = Release|Any CPU + {0ED336B7-6FAB-4872-8D75-1CDD5A5DDBB2}.Release|x86.Build.0 = Release|Any CPU + {FAFE3FF2-D36D-47DA-833D-C382A902705E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FAFE3FF2-D36D-47DA-833D-C382A902705E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FAFE3FF2-D36D-47DA-833D-C382A902705E}.Debug|x64.ActiveCfg = Debug|Any CPU + {FAFE3FF2-D36D-47DA-833D-C382A902705E}.Debug|x64.Build.0 = Debug|Any CPU + {FAFE3FF2-D36D-47DA-833D-C382A902705E}.Debug|x86.ActiveCfg = Debug|Any CPU + {FAFE3FF2-D36D-47DA-833D-C382A902705E}.Debug|x86.Build.0 = Debug|Any CPU + {FAFE3FF2-D36D-47DA-833D-C382A902705E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FAFE3FF2-D36D-47DA-833D-C382A902705E}.Release|Any CPU.Build.0 = Release|Any CPU + {FAFE3FF2-D36D-47DA-833D-C382A902705E}.Release|x64.ActiveCfg = Release|Any CPU + {FAFE3FF2-D36D-47DA-833D-C382A902705E}.Release|x64.Build.0 = Release|Any CPU + {FAFE3FF2-D36D-47DA-833D-C382A902705E}.Release|x86.ActiveCfg = Release|Any CPU + {FAFE3FF2-D36D-47DA-833D-C382A902705E}.Release|x86.Build.0 = Release|Any CPU + {2C10DF3B-D138-414A-BB36-02E45A7B6025}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2C10DF3B-D138-414A-BB36-02E45A7B6025}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2C10DF3B-D138-414A-BB36-02E45A7B6025}.Debug|x64.ActiveCfg = Debug|Any CPU + {2C10DF3B-D138-414A-BB36-02E45A7B6025}.Debug|x64.Build.0 = Debug|Any CPU + {2C10DF3B-D138-414A-BB36-02E45A7B6025}.Debug|x86.ActiveCfg = Debug|Any CPU + {2C10DF3B-D138-414A-BB36-02E45A7B6025}.Debug|x86.Build.0 = Debug|Any CPU + {2C10DF3B-D138-414A-BB36-02E45A7B6025}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2C10DF3B-D138-414A-BB36-02E45A7B6025}.Release|Any CPU.Build.0 = Release|Any CPU + {2C10DF3B-D138-414A-BB36-02E45A7B6025}.Release|x64.ActiveCfg = Release|Any CPU + {2C10DF3B-D138-414A-BB36-02E45A7B6025}.Release|x64.Build.0 = Release|Any CPU + {2C10DF3B-D138-414A-BB36-02E45A7B6025}.Release|x86.ActiveCfg = Release|Any CPU + {2C10DF3B-D138-414A-BB36-02E45A7B6025}.Release|x86.Build.0 = Release|Any CPU + {FBD7C733-200E-4BED-8B31-2610C2263F72}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FBD7C733-200E-4BED-8B31-2610C2263F72}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FBD7C733-200E-4BED-8B31-2610C2263F72}.Debug|x64.ActiveCfg = Debug|Any CPU + {FBD7C733-200E-4BED-8B31-2610C2263F72}.Debug|x64.Build.0 = Debug|Any CPU + {FBD7C733-200E-4BED-8B31-2610C2263F72}.Debug|x86.ActiveCfg = Debug|Any CPU + {FBD7C733-200E-4BED-8B31-2610C2263F72}.Debug|x86.Build.0 = Debug|Any CPU + {FBD7C733-200E-4BED-8B31-2610C2263F72}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FBD7C733-200E-4BED-8B31-2610C2263F72}.Release|Any CPU.Build.0 = Release|Any CPU + {FBD7C733-200E-4BED-8B31-2610C2263F72}.Release|x64.ActiveCfg = Release|Any CPU + {FBD7C733-200E-4BED-8B31-2610C2263F72}.Release|x64.Build.0 = Release|Any CPU + {FBD7C733-200E-4BED-8B31-2610C2263F72}.Release|x86.ActiveCfg = Release|Any CPU + {FBD7C733-200E-4BED-8B31-2610C2263F72}.Release|x86.Build.0 = Release|Any CPU + {BDBEDE12-74C1-466E-B8AE-49EC40F83866}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BDBEDE12-74C1-466E-B8AE-49EC40F83866}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BDBEDE12-74C1-466E-B8AE-49EC40F83866}.Debug|x64.ActiveCfg = Debug|Any CPU + {BDBEDE12-74C1-466E-B8AE-49EC40F83866}.Debug|x64.Build.0 = Debug|Any CPU + {BDBEDE12-74C1-466E-B8AE-49EC40F83866}.Debug|x86.ActiveCfg = Debug|Any CPU + {BDBEDE12-74C1-466E-B8AE-49EC40F83866}.Debug|x86.Build.0 = Debug|Any CPU + {BDBEDE12-74C1-466E-B8AE-49EC40F83866}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BDBEDE12-74C1-466E-B8AE-49EC40F83866}.Release|Any CPU.Build.0 = Release|Any CPU + {BDBEDE12-74C1-466E-B8AE-49EC40F83866}.Release|x64.ActiveCfg = Release|Any CPU + {BDBEDE12-74C1-466E-B8AE-49EC40F83866}.Release|x64.Build.0 = Release|Any CPU + {BDBEDE12-74C1-466E-B8AE-49EC40F83866}.Release|x86.ActiveCfg = Release|Any CPU + {BDBEDE12-74C1-466E-B8AE-49EC40F83866}.Release|x86.Build.0 = Release|Any CPU + {8276993E-3F54-4D2F-8DDA-E86F2C6BEF1E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8276993E-3F54-4D2F-8DDA-E86F2C6BEF1E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8276993E-3F54-4D2F-8DDA-E86F2C6BEF1E}.Debug|x64.ActiveCfg = Debug|Any CPU + {8276993E-3F54-4D2F-8DDA-E86F2C6BEF1E}.Debug|x64.Build.0 = Debug|Any CPU + {8276993E-3F54-4D2F-8DDA-E86F2C6BEF1E}.Debug|x86.ActiveCfg = Debug|Any CPU + {8276993E-3F54-4D2F-8DDA-E86F2C6BEF1E}.Debug|x86.Build.0 = Debug|Any CPU + {8276993E-3F54-4D2F-8DDA-E86F2C6BEF1E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8276993E-3F54-4D2F-8DDA-E86F2C6BEF1E}.Release|Any CPU.Build.0 = Release|Any CPU + {8276993E-3F54-4D2F-8DDA-E86F2C6BEF1E}.Release|x64.ActiveCfg = Release|Any CPU + {8276993E-3F54-4D2F-8DDA-E86F2C6BEF1E}.Release|x64.Build.0 = Release|Any CPU + {8276993E-3F54-4D2F-8DDA-E86F2C6BEF1E}.Release|x86.ActiveCfg = Release|Any CPU + {8276993E-3F54-4D2F-8DDA-E86F2C6BEF1E}.Release|x86.Build.0 = Release|Any CPU + {CFA20A59-F52B-47A2-BD5D-B600D9576BDA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CFA20A59-F52B-47A2-BD5D-B600D9576BDA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CFA20A59-F52B-47A2-BD5D-B600D9576BDA}.Debug|x64.ActiveCfg = Debug|Any CPU + {CFA20A59-F52B-47A2-BD5D-B600D9576BDA}.Debug|x64.Build.0 = Debug|Any CPU + {CFA20A59-F52B-47A2-BD5D-B600D9576BDA}.Debug|x86.ActiveCfg = Debug|Any CPU + {CFA20A59-F52B-47A2-BD5D-B600D9576BDA}.Debug|x86.Build.0 = Debug|Any CPU + {CFA20A59-F52B-47A2-BD5D-B600D9576BDA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CFA20A59-F52B-47A2-BD5D-B600D9576BDA}.Release|Any CPU.Build.0 = Release|Any CPU + {CFA20A59-F52B-47A2-BD5D-B600D9576BDA}.Release|x64.ActiveCfg = Release|Any CPU + {CFA20A59-F52B-47A2-BD5D-B600D9576BDA}.Release|x64.Build.0 = Release|Any CPU + {CFA20A59-F52B-47A2-BD5D-B600D9576BDA}.Release|x86.ActiveCfg = Release|Any CPU + {CFA20A59-F52B-47A2-BD5D-B600D9576BDA}.Release|x86.Build.0 = Release|Any CPU + {C97721BB-8D89-4167-9E59-839C237BA270}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C97721BB-8D89-4167-9E59-839C237BA270}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C97721BB-8D89-4167-9E59-839C237BA270}.Debug|x64.ActiveCfg = Debug|Any CPU + {C97721BB-8D89-4167-9E59-839C237BA270}.Debug|x64.Build.0 = Debug|Any CPU + {C97721BB-8D89-4167-9E59-839C237BA270}.Debug|x86.ActiveCfg = Debug|Any CPU + {C97721BB-8D89-4167-9E59-839C237BA270}.Debug|x86.Build.0 = Debug|Any CPU + {C97721BB-8D89-4167-9E59-839C237BA270}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C97721BB-8D89-4167-9E59-839C237BA270}.Release|Any CPU.Build.0 = Release|Any CPU + {C97721BB-8D89-4167-9E59-839C237BA270}.Release|x64.ActiveCfg = Release|Any CPU + {C97721BB-8D89-4167-9E59-839C237BA270}.Release|x64.Build.0 = Release|Any CPU + {C97721BB-8D89-4167-9E59-839C237BA270}.Release|x86.ActiveCfg = Release|Any CPU + {C97721BB-8D89-4167-9E59-839C237BA270}.Release|x86.Build.0 = Release|Any CPU + {7F357E7B-BF33-4055-9A21-37B3507BFF90}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7F357E7B-BF33-4055-9A21-37B3507BFF90}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7F357E7B-BF33-4055-9A21-37B3507BFF90}.Debug|x64.ActiveCfg = Debug|Any CPU + {7F357E7B-BF33-4055-9A21-37B3507BFF90}.Debug|x64.Build.0 = Debug|Any CPU + {7F357E7B-BF33-4055-9A21-37B3507BFF90}.Debug|x86.ActiveCfg = Debug|Any CPU + {7F357E7B-BF33-4055-9A21-37B3507BFF90}.Debug|x86.Build.0 = Debug|Any CPU + {7F357E7B-BF33-4055-9A21-37B3507BFF90}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7F357E7B-BF33-4055-9A21-37B3507BFF90}.Release|Any CPU.Build.0 = Release|Any CPU + {7F357E7B-BF33-4055-9A21-37B3507BFF90}.Release|x64.ActiveCfg = Release|Any CPU + {7F357E7B-BF33-4055-9A21-37B3507BFF90}.Release|x64.Build.0 = Release|Any CPU + {7F357E7B-BF33-4055-9A21-37B3507BFF90}.Release|x86.ActiveCfg = Release|Any CPU + {7F357E7B-BF33-4055-9A21-37B3507BFF90}.Release|x86.Build.0 = Release|Any CPU + {236FC110-FBE0-476D-ADC5-D98E23BAA1EE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {236FC110-FBE0-476D-ADC5-D98E23BAA1EE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {236FC110-FBE0-476D-ADC5-D98E23BAA1EE}.Debug|x64.ActiveCfg = Debug|Any CPU + {236FC110-FBE0-476D-ADC5-D98E23BAA1EE}.Debug|x64.Build.0 = Debug|Any CPU + {236FC110-FBE0-476D-ADC5-D98E23BAA1EE}.Debug|x86.ActiveCfg = Debug|Any CPU + {236FC110-FBE0-476D-ADC5-D98E23BAA1EE}.Debug|x86.Build.0 = Debug|Any CPU + {236FC110-FBE0-476D-ADC5-D98E23BAA1EE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {236FC110-FBE0-476D-ADC5-D98E23BAA1EE}.Release|Any CPU.Build.0 = Release|Any CPU + {236FC110-FBE0-476D-ADC5-D98E23BAA1EE}.Release|x64.ActiveCfg = Release|Any CPU + {236FC110-FBE0-476D-ADC5-D98E23BAA1EE}.Release|x64.Build.0 = Release|Any CPU + {236FC110-FBE0-476D-ADC5-D98E23BAA1EE}.Release|x86.ActiveCfg = Release|Any CPU + {236FC110-FBE0-476D-ADC5-D98E23BAA1EE}.Release|x86.Build.0 = Release|Any CPU + {52F0CF32-9506-4D9C-B715-52900B219BDF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {52F0CF32-9506-4D9C-B715-52900B219BDF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {52F0CF32-9506-4D9C-B715-52900B219BDF}.Debug|x64.ActiveCfg = Debug|Any CPU + {52F0CF32-9506-4D9C-B715-52900B219BDF}.Debug|x64.Build.0 = Debug|Any CPU + {52F0CF32-9506-4D9C-B715-52900B219BDF}.Debug|x86.ActiveCfg = Debug|Any CPU + {52F0CF32-9506-4D9C-B715-52900B219BDF}.Debug|x86.Build.0 = Debug|Any CPU + {52F0CF32-9506-4D9C-B715-52900B219BDF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {52F0CF32-9506-4D9C-B715-52900B219BDF}.Release|Any CPU.Build.0 = Release|Any CPU + {52F0CF32-9506-4D9C-B715-52900B219BDF}.Release|x64.ActiveCfg = Release|Any CPU + {52F0CF32-9506-4D9C-B715-52900B219BDF}.Release|x64.Build.0 = Release|Any CPU + {52F0CF32-9506-4D9C-B715-52900B219BDF}.Release|x86.ActiveCfg = Release|Any CPU + {52F0CF32-9506-4D9C-B715-52900B219BDF}.Release|x86.Build.0 = Release|Any CPU + {C1CC2480-7925-4391-86F5-60653D864E87}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C1CC2480-7925-4391-86F5-60653D864E87}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C1CC2480-7925-4391-86F5-60653D864E87}.Debug|x64.ActiveCfg = Debug|Any CPU + {C1CC2480-7925-4391-86F5-60653D864E87}.Debug|x64.Build.0 = Debug|Any CPU + {C1CC2480-7925-4391-86F5-60653D864E87}.Debug|x86.ActiveCfg = Debug|Any CPU + {C1CC2480-7925-4391-86F5-60653D864E87}.Debug|x86.Build.0 = Debug|Any CPU + {C1CC2480-7925-4391-86F5-60653D864E87}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C1CC2480-7925-4391-86F5-60653D864E87}.Release|Any CPU.Build.0 = Release|Any CPU + {C1CC2480-7925-4391-86F5-60653D864E87}.Release|x64.ActiveCfg = Release|Any CPU + {C1CC2480-7925-4391-86F5-60653D864E87}.Release|x64.Build.0 = Release|Any CPU + {C1CC2480-7925-4391-86F5-60653D864E87}.Release|x86.ActiveCfg = Release|Any CPU + {C1CC2480-7925-4391-86F5-60653D864E87}.Release|x86.Build.0 = Release|Any CPU + {2DD2A221-255E-4A57-A2C3-B24C9BDC2E24}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2DD2A221-255E-4A57-A2C3-B24C9BDC2E24}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2DD2A221-255E-4A57-A2C3-B24C9BDC2E24}.Debug|x64.ActiveCfg = Debug|Any CPU + {2DD2A221-255E-4A57-A2C3-B24C9BDC2E24}.Debug|x64.Build.0 = Debug|Any CPU + {2DD2A221-255E-4A57-A2C3-B24C9BDC2E24}.Debug|x86.ActiveCfg = Debug|Any CPU + {2DD2A221-255E-4A57-A2C3-B24C9BDC2E24}.Debug|x86.Build.0 = Debug|Any CPU + {2DD2A221-255E-4A57-A2C3-B24C9BDC2E24}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2DD2A221-255E-4A57-A2C3-B24C9BDC2E24}.Release|Any CPU.Build.0 = Release|Any CPU + {2DD2A221-255E-4A57-A2C3-B24C9BDC2E24}.Release|x64.ActiveCfg = Release|Any CPU + {2DD2A221-255E-4A57-A2C3-B24C9BDC2E24}.Release|x64.Build.0 = Release|Any CPU + {2DD2A221-255E-4A57-A2C3-B24C9BDC2E24}.Release|x86.ActiveCfg = Release|Any CPU + {2DD2A221-255E-4A57-A2C3-B24C9BDC2E24}.Release|x86.Build.0 = Release|Any CPU + {376D8A5F-923C-4AF9-8627-EA0E8E54AEDF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {376D8A5F-923C-4AF9-8627-EA0E8E54AEDF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {376D8A5F-923C-4AF9-8627-EA0E8E54AEDF}.Debug|x64.ActiveCfg = Debug|Any CPU + {376D8A5F-923C-4AF9-8627-EA0E8E54AEDF}.Debug|x64.Build.0 = Debug|Any CPU + {376D8A5F-923C-4AF9-8627-EA0E8E54AEDF}.Debug|x86.ActiveCfg = Debug|Any CPU + {376D8A5F-923C-4AF9-8627-EA0E8E54AEDF}.Debug|x86.Build.0 = Debug|Any CPU + {376D8A5F-923C-4AF9-8627-EA0E8E54AEDF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {376D8A5F-923C-4AF9-8627-EA0E8E54AEDF}.Release|Any CPU.Build.0 = Release|Any CPU + {376D8A5F-923C-4AF9-8627-EA0E8E54AEDF}.Release|x64.ActiveCfg = Release|Any CPU + {376D8A5F-923C-4AF9-8627-EA0E8E54AEDF}.Release|x64.Build.0 = Release|Any CPU + {376D8A5F-923C-4AF9-8627-EA0E8E54AEDF}.Release|x86.ActiveCfg = Release|Any CPU + {376D8A5F-923C-4AF9-8627-EA0E8E54AEDF}.Release|x86.Build.0 = Release|Any CPU + {1B633436-B999-467F-8A8F-778BB075CD35}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1B633436-B999-467F-8A8F-778BB075CD35}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1B633436-B999-467F-8A8F-778BB075CD35}.Debug|x64.ActiveCfg = Debug|Any CPU + {1B633436-B999-467F-8A8F-778BB075CD35}.Debug|x64.Build.0 = Debug|Any CPU + {1B633436-B999-467F-8A8F-778BB075CD35}.Debug|x86.ActiveCfg = Debug|Any CPU + {1B633436-B999-467F-8A8F-778BB075CD35}.Debug|x86.Build.0 = Debug|Any CPU + {1B633436-B999-467F-8A8F-778BB075CD35}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1B633436-B999-467F-8A8F-778BB075CD35}.Release|Any CPU.Build.0 = Release|Any CPU + {1B633436-B999-467F-8A8F-778BB075CD35}.Release|x64.ActiveCfg = Release|Any CPU + {1B633436-B999-467F-8A8F-778BB075CD35}.Release|x64.Build.0 = Release|Any CPU + {1B633436-B999-467F-8A8F-778BB075CD35}.Release|x86.ActiveCfg = Release|Any CPU + {1B633436-B999-467F-8A8F-778BB075CD35}.Release|x86.Build.0 = Release|Any CPU + {DA17FB91-EF6F-4C34-A5D4-1A0F7E42D699}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DA17FB91-EF6F-4C34-A5D4-1A0F7E42D699}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DA17FB91-EF6F-4C34-A5D4-1A0F7E42D699}.Debug|x64.ActiveCfg = Debug|Any CPU + {DA17FB91-EF6F-4C34-A5D4-1A0F7E42D699}.Debug|x64.Build.0 = Debug|Any CPU + {DA17FB91-EF6F-4C34-A5D4-1A0F7E42D699}.Debug|x86.ActiveCfg = Debug|Any CPU + {DA17FB91-EF6F-4C34-A5D4-1A0F7E42D699}.Debug|x86.Build.0 = Debug|Any CPU + {DA17FB91-EF6F-4C34-A5D4-1A0F7E42D699}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DA17FB91-EF6F-4C34-A5D4-1A0F7E42D699}.Release|Any CPU.Build.0 = Release|Any CPU + {DA17FB91-EF6F-4C34-A5D4-1A0F7E42D699}.Release|x64.ActiveCfg = Release|Any CPU + {DA17FB91-EF6F-4C34-A5D4-1A0F7E42D699}.Release|x64.Build.0 = Release|Any CPU + {DA17FB91-EF6F-4C34-A5D4-1A0F7E42D699}.Release|x86.ActiveCfg = Release|Any CPU + {DA17FB91-EF6F-4C34-A5D4-1A0F7E42D699}.Release|x86.Build.0 = Release|Any CPU + {BC3DDF14-4961-49AB-8F19-2A23F535B0DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BC3DDF14-4961-49AB-8F19-2A23F535B0DE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BC3DDF14-4961-49AB-8F19-2A23F535B0DE}.Debug|x64.ActiveCfg = Debug|Any CPU + {BC3DDF14-4961-49AB-8F19-2A23F535B0DE}.Debug|x64.Build.0 = Debug|Any CPU + {BC3DDF14-4961-49AB-8F19-2A23F535B0DE}.Debug|x86.ActiveCfg = Debug|Any CPU + {BC3DDF14-4961-49AB-8F19-2A23F535B0DE}.Debug|x86.Build.0 = Debug|Any CPU + {BC3DDF14-4961-49AB-8F19-2A23F535B0DE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BC3DDF14-4961-49AB-8F19-2A23F535B0DE}.Release|Any CPU.Build.0 = Release|Any CPU + {BC3DDF14-4961-49AB-8F19-2A23F535B0DE}.Release|x64.ActiveCfg = Release|Any CPU + {BC3DDF14-4961-49AB-8F19-2A23F535B0DE}.Release|x64.Build.0 = Release|Any CPU + {BC3DDF14-4961-49AB-8F19-2A23F535B0DE}.Release|x86.ActiveCfg = Release|Any CPU + {BC3DDF14-4961-49AB-8F19-2A23F535B0DE}.Release|x86.Build.0 = Release|Any CPU + {EACC194A-8C1B-424D-B8FE-330E14CAF525}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EACC194A-8C1B-424D-B8FE-330E14CAF525}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EACC194A-8C1B-424D-B8FE-330E14CAF525}.Debug|x64.ActiveCfg = Debug|Any CPU + {EACC194A-8C1B-424D-B8FE-330E14CAF525}.Debug|x64.Build.0 = Debug|Any CPU + {EACC194A-8C1B-424D-B8FE-330E14CAF525}.Debug|x86.ActiveCfg = Debug|Any CPU + {EACC194A-8C1B-424D-B8FE-330E14CAF525}.Debug|x86.Build.0 = Debug|Any CPU + {EACC194A-8C1B-424D-B8FE-330E14CAF525}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EACC194A-8C1B-424D-B8FE-330E14CAF525}.Release|Any CPU.Build.0 = Release|Any CPU + {EACC194A-8C1B-424D-B8FE-330E14CAF525}.Release|x64.ActiveCfg = Release|Any CPU + {EACC194A-8C1B-424D-B8FE-330E14CAF525}.Release|x64.Build.0 = Release|Any CPU + {EACC194A-8C1B-424D-B8FE-330E14CAF525}.Release|x86.ActiveCfg = Release|Any CPU + {EACC194A-8C1B-424D-B8FE-330E14CAF525}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {9B360D1A-5355-4942-B77E-76A1AC67911B} = {46E744CC-D332-401F-B074-A40341F0F832} + {85E2777A-F8E0-48B8-9FC4-B60FDC7B45B7} = {9B360D1A-5355-4942-B77E-76A1AC67911B} + {10E5AD2E-25A9-4B8B-BD33-207B12D5BAE4} = {9B360D1A-5355-4942-B77E-76A1AC67911B} + {E363191C-6C15-4C40-8698-B0AD5AA09700} = {B29FB58D-FAE5-405E-9695-BCF93582BE9A} + {8A585A38-917D-4A7E-8AFD-E860C76878FA} = {E363191C-6C15-4C40-8698-B0AD5AA09700} + {75DA4341-5B7F-419C-8EED-3492013D8EB5} = {E363191C-6C15-4C40-8698-B0AD5AA09700} + {A82B9830-447D-4E26-BEB7-C724A3956C0D} = {B29FB58D-FAE5-405E-9695-BCF93582BE9A} + {201D53B3-2D33-40AD-813F-347A0C1998ED} = {A82B9830-447D-4E26-BEB7-C724A3956C0D} + {AB13059F-8F21-48F6-B9F3-EAF260D9CB81} = {A82B9830-447D-4E26-BEB7-C724A3956C0D} + {B4ACD900-27B6-482B-B434-2C1E86E9D8BC} = {A82B9830-447D-4E26-BEB7-C724A3956C0D} + {5F44DC59-3B4E-4E87-973F-C9FB4BBFD03D} = {B4ACD900-27B6-482B-B434-2C1E86E9D8BC} + {4BD2D530-83C7-4A86-AF8E-FE1FECBF64C6} = {B4ACD900-27B6-482B-B434-2C1E86E9D8BC} + {779749F3-8D4F-42BD-9219-37502AD68F0E} = {B4ACD900-27B6-482B-B434-2C1E86E9D8BC} + {9C41BA92-FBC8-4E11-9A71-0B07906A2D6C} = {B4ACD900-27B6-482B-B434-2C1E86E9D8BC} + {A44FB7D1-78AB-41C4-B1C7-94399396EA6C} = {B29FB58D-FAE5-405E-9695-BCF93582BE9A} + {0ED336B7-6FAB-4872-8D75-1CDD5A5DDBB2} = {A44FB7D1-78AB-41C4-B1C7-94399396EA6C} + {F4995C96-8D4E-4B26-8FB8-614B020156C2} = {B29FB58D-FAE5-405E-9695-BCF93582BE9A} + {FAFE3FF2-D36D-47DA-833D-C382A902705E} = {F4995C96-8D4E-4B26-8FB8-614B020156C2} + {2C10DF3B-D138-414A-BB36-02E45A7B6025} = {F4995C96-8D4E-4B26-8FB8-614B020156C2} + {37FA056D-A7B3-4F72-A8B9-8D3C175E831E} = {B29FB58D-FAE5-405E-9695-BCF93582BE9A} + {FBD7C733-200E-4BED-8B31-2610C2263F72} = {37FA056D-A7B3-4F72-A8B9-8D3C175E831E} + {7920B09F-8016-49CF-A229-E72D0CECDD17} = {B29FB58D-FAE5-405E-9695-BCF93582BE9A} + {BDBEDE12-74C1-466E-B8AE-49EC40F83866} = {7920B09F-8016-49CF-A229-E72D0CECDD17} + {CBD2BB24-3EC3-4950-ABE4-8C521D258DCD} = {B29FB58D-FAE5-405E-9695-BCF93582BE9A} + {8276993E-3F54-4D2F-8DDA-E86F2C6BEF1E} = {CBD2BB24-3EC3-4950-ABE4-8C521D258DCD} + {CFA20A59-F52B-47A2-BD5D-B600D9576BDA} = {CBD2BB24-3EC3-4950-ABE4-8C521D258DCD} + {C97721BB-8D89-4167-9E59-839C237BA270} = {CBD2BB24-3EC3-4950-ABE4-8C521D258DCD} + {7F357E7B-BF33-4055-9A21-37B3507BFF90} = {CBD2BB24-3EC3-4950-ABE4-8C521D258DCD} + {236FC110-FBE0-476D-ADC5-D98E23BAA1EE} = {CBD2BB24-3EC3-4950-ABE4-8C521D258DCD} + {09758C93-6707-46E3-9211-470449280C2C} = {B29FB58D-FAE5-405E-9695-BCF93582BE9A} + {52F0CF32-9506-4D9C-B715-52900B219BDF} = {09758C93-6707-46E3-9211-470449280C2C} + {C1CC2480-7925-4391-86F5-60653D864E87} = {09758C93-6707-46E3-9211-470449280C2C} + {2DD2A221-255E-4A57-A2C3-B24C9BDC2E24} = {194596E0-E6F5-4728-8A7A-A82EA0893111} + {10C06583-8506-42DE-863E-EAD48A1F7579} = {194596E0-E6F5-4728-8A7A-A82EA0893111} + {376D8A5F-923C-4AF9-8627-EA0E8E54AEDF} = {10C06583-8506-42DE-863E-EAD48A1F7579} + {1B633436-B999-467F-8A8F-778BB075CD35} = {10C06583-8506-42DE-863E-EAD48A1F7579} + {DA17FB91-EF6F-4C34-A5D4-1A0F7E42D699} = {10C06583-8506-42DE-863E-EAD48A1F7579} + {BC3DDF14-4961-49AB-8F19-2A23F535B0DE} = {10C06583-8506-42DE-863E-EAD48A1F7579} + {EACC194A-8C1B-424D-B8FE-330E14CAF525} = {10C06583-8506-42DE-863E-EAD48A1F7579} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {27A36094-AA50-4FFD-ADE6-C055E391F741} + EndGlobalSection +EndGlobal diff --git a/src/Components/Blazor/Blazor.sln b/src/Components/Blazor/Blazor.sln new file mode 100644 index 0000000000..b8c2890be1 --- /dev/null +++ b/src/Components/Blazor/Blazor.sln @@ -0,0 +1,440 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26124.0 +MinimumVisualStudioVersion = 15.0.26124.0 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Blazor", "Blazor", "{8AD7BBC4-892F-4F45-A239-622DA6C181ED}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.Blazor", "Blazor\ref\Microsoft.AspNetCore.Blazor.csproj", "{549D1333-970B-4C0B-80E1-E96C910A4DBD}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.Blazor", "Blazor\src\Microsoft.AspNetCore.Blazor.csproj", "{53E70BA4-4B34-43A4-B6F9-9BEC482650AD}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.Blazor.Tests", "Blazor\test\Microsoft.AspNetCore.Blazor.Tests.csproj", "{0A500F50-2CA6-4FD1-B01D-F4E1D33CCCC9}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{BE77AC33-F34A-41B4-A22F-DB45A4B8E49C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.Blazor.Build", "Build\src\Microsoft.AspNetCore.Blazor.Build.csproj", "{814B9486-A590-4C70-A323-3C1118DB5AA2}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.Blazor.Build.Tests", "Build\test\Microsoft.AspNetCore.Blazor.Build.Tests.csproj", "{669396CA-E180-4536-BB9D-565DF522964B}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "testassets", "testassets", "{0BD0C661-CEDD-4D64-BAC8-3947D9AD21F2}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "blazorhosted", "Build\testassets\blazorhosted\blazorhosted.csproj", "{D4C040D5-598E-43DB-8341-B1E14368DBE2}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "classlibrarywithsatelliteassemblies", "Build\testassets\classlibrarywithsatelliteassemblies\classlibrarywithsatelliteassemblies.csproj", "{EF440F94-84ED-43DB-8D8B-671B1F345B84}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RazorClassLibrary", "Build\testassets\razorclasslibrary\RazorClassLibrary.csproj", "{C5AE51C7-47CD-489C-80CD-799209DAA0E5}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "standalone", "Build\testassets\standalone\standalone.csproj", "{92B77A61-B60C-4F4E-96FF-C34BEEAD2D54}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DevServer", "DevServer", "{0B6A1C60-596A-45A8-A71E-940F463F5C0D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.Blazor.DevServer", "DevServer\src\Microsoft.AspNetCore.Blazor.DevServer.csproj", "{DD96E545-2466-4531-8F3A-D588871A4D19}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Http", "Http", "{4FD7794A-3AB7-4455-9EA6-392CEE415588}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.Blazor.HttpClient", "Http\src\Microsoft.AspNetCore.Blazor.HttpClient.csproj", "{8EDF0733-D5DD-4D30-8E08-05EB69DD99B7}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.Blazor.HttpClient.Tests", "Http\test\Microsoft.AspNetCore.Blazor.HttpClient.Tests.csproj", "{1EEEF8C8-EA17-4D84-B1CE-870153C7D5DA}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Mono.WebAssembly.Interop", "Mono.WebAssembly.Interop", "{6D83D4EC-451D-40B9-BF80-475667CC5DFE}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.WebAssembly.Interop", "Mono.WebAssembly.Interop\src\Mono.WebAssembly.Interop.csproj", "{6E3190E9-49D7-4E40-A8C6-A29519E4A6FC}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Server", "Server", "{3BCD0E35-4CBA-4A14-80D8-9D695F14A384}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.Blazor.Server", "Server\src\Microsoft.AspNetCore.Blazor.Server.csproj", "{70143EFD-F167-4D8F-A4C1-201DD00C864E}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "testassets", "testassets", "{185140F7-1F8F-430F-BC47-63C2712AC67F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HostedInAspNet.Client", "testassets\HostedInAspNet.Client\HostedInAspNet.Client.csproj", "{9036CD3D-6B45-4B2C-8F69-C6C4D98DCF7D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HostedInAspNet.Server", "testassets\HostedInAspNet.Server\HostedInAspNet.Server.csproj", "{02054BB0-BBBD-45BA-8260-040126E98A8D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MonoSanity", "testassets\MonoSanity\MonoSanity.csproj", "{02EFF071-DC63-4B96-9B1C-8BCAEF22BDA2}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MonoSanityClient", "testassets\MonoSanityClient\MonoSanityClient.csproj", "{3605D881-E511-46E4-B80B-5BFF98DA8A9C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StandaloneApp", "testassets\StandaloneApp\StandaloneApp.csproj", "{3293A32D-36DF-4A8A-99F5-E35E86B48F45}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Validation", "Validation", "{BD3AE379-14B5-4ABD-AF0E-023715D9726F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.Blazor.DataAnnotations.Validation", "Validation\src\Microsoft.AspNetCore.Blazor.DataAnnotations.Validation.csproj", "{E0F4A65D-F0BB-4EED-ADE8-B514E0F82971}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.Blazor.DataAnnotations.Validation.Tests", "Validation\test\Microsoft.AspNetCore.Blazor.DataAnnotations.Validation.Tests.csproj", "{92113D6B-04C3-456C-867B-87DDF02A796A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.Components.E2ETests", "..\test\E2ETest\Microsoft.AspNetCore.Components.E2ETests.csproj", "{86002AE6-8317-4451-A649-8E95AC5148F6}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BasicTestApp", "..\test\testassets\BasicTestApp\BasicTestApp.csproj", "{8997D5A8-097E-46F9-9B99-D9A367A1B1EE}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ComponentsApp.App", "..\test\testassets\ComponentsApp.App\ComponentsApp.App.csproj", "{98F9E296-DB25-4EFB-AB0F-549602F8FC16}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ComponentsApp.Server", "..\test\testassets\ComponentsApp.Server\ComponentsApp.Server.csproj", "{8E9F474B-D58C-49C4-8EDB-8A9BDBA3F98A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestContentPackage", "..\test\testassets\TestContentPackage\TestContentPackage.csproj", "{FB0DA201-C124-4DE6-AFCD-7996C2C05BD0}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Components.TestServer", "..\test\testassets\TestServer\Components.TestServer.csproj", "{D117C434-D16D-4E38-A8B7-4663944CE167}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {549D1333-970B-4C0B-80E1-E96C910A4DBD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {549D1333-970B-4C0B-80E1-E96C910A4DBD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {549D1333-970B-4C0B-80E1-E96C910A4DBD}.Debug|x64.ActiveCfg = Debug|Any CPU + {549D1333-970B-4C0B-80E1-E96C910A4DBD}.Debug|x64.Build.0 = Debug|Any CPU + {549D1333-970B-4C0B-80E1-E96C910A4DBD}.Debug|x86.ActiveCfg = Debug|Any CPU + {549D1333-970B-4C0B-80E1-E96C910A4DBD}.Debug|x86.Build.0 = Debug|Any CPU + {549D1333-970B-4C0B-80E1-E96C910A4DBD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {549D1333-970B-4C0B-80E1-E96C910A4DBD}.Release|Any CPU.Build.0 = Release|Any CPU + {549D1333-970B-4C0B-80E1-E96C910A4DBD}.Release|x64.ActiveCfg = Release|Any CPU + {549D1333-970B-4C0B-80E1-E96C910A4DBD}.Release|x64.Build.0 = Release|Any CPU + {549D1333-970B-4C0B-80E1-E96C910A4DBD}.Release|x86.ActiveCfg = Release|Any CPU + {549D1333-970B-4C0B-80E1-E96C910A4DBD}.Release|x86.Build.0 = Release|Any CPU + {53E70BA4-4B34-43A4-B6F9-9BEC482650AD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {53E70BA4-4B34-43A4-B6F9-9BEC482650AD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {53E70BA4-4B34-43A4-B6F9-9BEC482650AD}.Debug|x64.ActiveCfg = Debug|Any CPU + {53E70BA4-4B34-43A4-B6F9-9BEC482650AD}.Debug|x64.Build.0 = Debug|Any CPU + {53E70BA4-4B34-43A4-B6F9-9BEC482650AD}.Debug|x86.ActiveCfg = Debug|Any CPU + {53E70BA4-4B34-43A4-B6F9-9BEC482650AD}.Debug|x86.Build.0 = Debug|Any CPU + {53E70BA4-4B34-43A4-B6F9-9BEC482650AD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {53E70BA4-4B34-43A4-B6F9-9BEC482650AD}.Release|Any CPU.Build.0 = Release|Any CPU + {53E70BA4-4B34-43A4-B6F9-9BEC482650AD}.Release|x64.ActiveCfg = Release|Any CPU + {53E70BA4-4B34-43A4-B6F9-9BEC482650AD}.Release|x64.Build.0 = Release|Any CPU + {53E70BA4-4B34-43A4-B6F9-9BEC482650AD}.Release|x86.ActiveCfg = Release|Any CPU + {53E70BA4-4B34-43A4-B6F9-9BEC482650AD}.Release|x86.Build.0 = Release|Any CPU + {0A500F50-2CA6-4FD1-B01D-F4E1D33CCCC9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0A500F50-2CA6-4FD1-B01D-F4E1D33CCCC9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0A500F50-2CA6-4FD1-B01D-F4E1D33CCCC9}.Debug|x64.ActiveCfg = Debug|Any CPU + {0A500F50-2CA6-4FD1-B01D-F4E1D33CCCC9}.Debug|x64.Build.0 = Debug|Any CPU + {0A500F50-2CA6-4FD1-B01D-F4E1D33CCCC9}.Debug|x86.ActiveCfg = Debug|Any CPU + {0A500F50-2CA6-4FD1-B01D-F4E1D33CCCC9}.Debug|x86.Build.0 = Debug|Any CPU + {0A500F50-2CA6-4FD1-B01D-F4E1D33CCCC9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0A500F50-2CA6-4FD1-B01D-F4E1D33CCCC9}.Release|Any CPU.Build.0 = Release|Any CPU + {0A500F50-2CA6-4FD1-B01D-F4E1D33CCCC9}.Release|x64.ActiveCfg = Release|Any CPU + {0A500F50-2CA6-4FD1-B01D-F4E1D33CCCC9}.Release|x64.Build.0 = Release|Any CPU + {0A500F50-2CA6-4FD1-B01D-F4E1D33CCCC9}.Release|x86.ActiveCfg = Release|Any CPU + {0A500F50-2CA6-4FD1-B01D-F4E1D33CCCC9}.Release|x86.Build.0 = Release|Any CPU + {814B9486-A590-4C70-A323-3C1118DB5AA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {814B9486-A590-4C70-A323-3C1118DB5AA2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {814B9486-A590-4C70-A323-3C1118DB5AA2}.Debug|x64.ActiveCfg = Debug|Any CPU + {814B9486-A590-4C70-A323-3C1118DB5AA2}.Debug|x64.Build.0 = Debug|Any CPU + {814B9486-A590-4C70-A323-3C1118DB5AA2}.Debug|x86.ActiveCfg = Debug|Any CPU + {814B9486-A590-4C70-A323-3C1118DB5AA2}.Debug|x86.Build.0 = Debug|Any CPU + {814B9486-A590-4C70-A323-3C1118DB5AA2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {814B9486-A590-4C70-A323-3C1118DB5AA2}.Release|Any CPU.Build.0 = Release|Any CPU + {814B9486-A590-4C70-A323-3C1118DB5AA2}.Release|x64.ActiveCfg = Release|Any CPU + {814B9486-A590-4C70-A323-3C1118DB5AA2}.Release|x64.Build.0 = Release|Any CPU + {814B9486-A590-4C70-A323-3C1118DB5AA2}.Release|x86.ActiveCfg = Release|Any CPU + {814B9486-A590-4C70-A323-3C1118DB5AA2}.Release|x86.Build.0 = Release|Any CPU + {669396CA-E180-4536-BB9D-565DF522964B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {669396CA-E180-4536-BB9D-565DF522964B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {669396CA-E180-4536-BB9D-565DF522964B}.Debug|x64.ActiveCfg = Debug|Any CPU + {669396CA-E180-4536-BB9D-565DF522964B}.Debug|x64.Build.0 = Debug|Any CPU + {669396CA-E180-4536-BB9D-565DF522964B}.Debug|x86.ActiveCfg = Debug|Any CPU + {669396CA-E180-4536-BB9D-565DF522964B}.Debug|x86.Build.0 = Debug|Any CPU + {669396CA-E180-4536-BB9D-565DF522964B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {669396CA-E180-4536-BB9D-565DF522964B}.Release|Any CPU.Build.0 = Release|Any CPU + {669396CA-E180-4536-BB9D-565DF522964B}.Release|x64.ActiveCfg = Release|Any CPU + {669396CA-E180-4536-BB9D-565DF522964B}.Release|x64.Build.0 = Release|Any CPU + {669396CA-E180-4536-BB9D-565DF522964B}.Release|x86.ActiveCfg = Release|Any CPU + {669396CA-E180-4536-BB9D-565DF522964B}.Release|x86.Build.0 = Release|Any CPU + {D4C040D5-598E-43DB-8341-B1E14368DBE2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D4C040D5-598E-43DB-8341-B1E14368DBE2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D4C040D5-598E-43DB-8341-B1E14368DBE2}.Debug|x64.ActiveCfg = Debug|Any CPU + {D4C040D5-598E-43DB-8341-B1E14368DBE2}.Debug|x64.Build.0 = Debug|Any CPU + {D4C040D5-598E-43DB-8341-B1E14368DBE2}.Debug|x86.ActiveCfg = Debug|Any CPU + {D4C040D5-598E-43DB-8341-B1E14368DBE2}.Debug|x86.Build.0 = Debug|Any CPU + {D4C040D5-598E-43DB-8341-B1E14368DBE2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D4C040D5-598E-43DB-8341-B1E14368DBE2}.Release|Any CPU.Build.0 = Release|Any CPU + {D4C040D5-598E-43DB-8341-B1E14368DBE2}.Release|x64.ActiveCfg = Release|Any CPU + {D4C040D5-598E-43DB-8341-B1E14368DBE2}.Release|x64.Build.0 = Release|Any CPU + {D4C040D5-598E-43DB-8341-B1E14368DBE2}.Release|x86.ActiveCfg = Release|Any CPU + {D4C040D5-598E-43DB-8341-B1E14368DBE2}.Release|x86.Build.0 = Release|Any CPU + {EF440F94-84ED-43DB-8D8B-671B1F345B84}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EF440F94-84ED-43DB-8D8B-671B1F345B84}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EF440F94-84ED-43DB-8D8B-671B1F345B84}.Debug|x64.ActiveCfg = Debug|Any CPU + {EF440F94-84ED-43DB-8D8B-671B1F345B84}.Debug|x64.Build.0 = Debug|Any CPU + {EF440F94-84ED-43DB-8D8B-671B1F345B84}.Debug|x86.ActiveCfg = Debug|Any CPU + {EF440F94-84ED-43DB-8D8B-671B1F345B84}.Debug|x86.Build.0 = Debug|Any CPU + {EF440F94-84ED-43DB-8D8B-671B1F345B84}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EF440F94-84ED-43DB-8D8B-671B1F345B84}.Release|Any CPU.Build.0 = Release|Any CPU + {EF440F94-84ED-43DB-8D8B-671B1F345B84}.Release|x64.ActiveCfg = Release|Any CPU + {EF440F94-84ED-43DB-8D8B-671B1F345B84}.Release|x64.Build.0 = Release|Any CPU + {EF440F94-84ED-43DB-8D8B-671B1F345B84}.Release|x86.ActiveCfg = Release|Any CPU + {EF440F94-84ED-43DB-8D8B-671B1F345B84}.Release|x86.Build.0 = Release|Any CPU + {C5AE51C7-47CD-489C-80CD-799209DAA0E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C5AE51C7-47CD-489C-80CD-799209DAA0E5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C5AE51C7-47CD-489C-80CD-799209DAA0E5}.Debug|x64.ActiveCfg = Debug|Any CPU + {C5AE51C7-47CD-489C-80CD-799209DAA0E5}.Debug|x64.Build.0 = Debug|Any CPU + {C5AE51C7-47CD-489C-80CD-799209DAA0E5}.Debug|x86.ActiveCfg = Debug|Any CPU + {C5AE51C7-47CD-489C-80CD-799209DAA0E5}.Debug|x86.Build.0 = Debug|Any CPU + {C5AE51C7-47CD-489C-80CD-799209DAA0E5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C5AE51C7-47CD-489C-80CD-799209DAA0E5}.Release|Any CPU.Build.0 = Release|Any CPU + {C5AE51C7-47CD-489C-80CD-799209DAA0E5}.Release|x64.ActiveCfg = Release|Any CPU + {C5AE51C7-47CD-489C-80CD-799209DAA0E5}.Release|x64.Build.0 = Release|Any CPU + {C5AE51C7-47CD-489C-80CD-799209DAA0E5}.Release|x86.ActiveCfg = Release|Any CPU + {C5AE51C7-47CD-489C-80CD-799209DAA0E5}.Release|x86.Build.0 = Release|Any CPU + {92B77A61-B60C-4F4E-96FF-C34BEEAD2D54}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {92B77A61-B60C-4F4E-96FF-C34BEEAD2D54}.Debug|Any CPU.Build.0 = Debug|Any CPU + {92B77A61-B60C-4F4E-96FF-C34BEEAD2D54}.Debug|x64.ActiveCfg = Debug|Any CPU + {92B77A61-B60C-4F4E-96FF-C34BEEAD2D54}.Debug|x64.Build.0 = Debug|Any CPU + {92B77A61-B60C-4F4E-96FF-C34BEEAD2D54}.Debug|x86.ActiveCfg = Debug|Any CPU + {92B77A61-B60C-4F4E-96FF-C34BEEAD2D54}.Debug|x86.Build.0 = Debug|Any CPU + {92B77A61-B60C-4F4E-96FF-C34BEEAD2D54}.Release|Any CPU.ActiveCfg = Release|Any CPU + {92B77A61-B60C-4F4E-96FF-C34BEEAD2D54}.Release|Any CPU.Build.0 = Release|Any CPU + {92B77A61-B60C-4F4E-96FF-C34BEEAD2D54}.Release|x64.ActiveCfg = Release|Any CPU + {92B77A61-B60C-4F4E-96FF-C34BEEAD2D54}.Release|x64.Build.0 = Release|Any CPU + {92B77A61-B60C-4F4E-96FF-C34BEEAD2D54}.Release|x86.ActiveCfg = Release|Any CPU + {92B77A61-B60C-4F4E-96FF-C34BEEAD2D54}.Release|x86.Build.0 = Release|Any CPU + {DD96E545-2466-4531-8F3A-D588871A4D19}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DD96E545-2466-4531-8F3A-D588871A4D19}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DD96E545-2466-4531-8F3A-D588871A4D19}.Debug|x64.ActiveCfg = Debug|Any CPU + {DD96E545-2466-4531-8F3A-D588871A4D19}.Debug|x64.Build.0 = Debug|Any CPU + {DD96E545-2466-4531-8F3A-D588871A4D19}.Debug|x86.ActiveCfg = Debug|Any CPU + {DD96E545-2466-4531-8F3A-D588871A4D19}.Debug|x86.Build.0 = Debug|Any CPU + {DD96E545-2466-4531-8F3A-D588871A4D19}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DD96E545-2466-4531-8F3A-D588871A4D19}.Release|Any CPU.Build.0 = Release|Any CPU + {DD96E545-2466-4531-8F3A-D588871A4D19}.Release|x64.ActiveCfg = Release|Any CPU + {DD96E545-2466-4531-8F3A-D588871A4D19}.Release|x64.Build.0 = Release|Any CPU + {DD96E545-2466-4531-8F3A-D588871A4D19}.Release|x86.ActiveCfg = Release|Any CPU + {DD96E545-2466-4531-8F3A-D588871A4D19}.Release|x86.Build.0 = Release|Any CPU + {8EDF0733-D5DD-4D30-8E08-05EB69DD99B7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8EDF0733-D5DD-4D30-8E08-05EB69DD99B7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8EDF0733-D5DD-4D30-8E08-05EB69DD99B7}.Debug|x64.ActiveCfg = Debug|Any CPU + {8EDF0733-D5DD-4D30-8E08-05EB69DD99B7}.Debug|x64.Build.0 = Debug|Any CPU + {8EDF0733-D5DD-4D30-8E08-05EB69DD99B7}.Debug|x86.ActiveCfg = Debug|Any CPU + {8EDF0733-D5DD-4D30-8E08-05EB69DD99B7}.Debug|x86.Build.0 = Debug|Any CPU + {8EDF0733-D5DD-4D30-8E08-05EB69DD99B7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8EDF0733-D5DD-4D30-8E08-05EB69DD99B7}.Release|Any CPU.Build.0 = Release|Any CPU + {8EDF0733-D5DD-4D30-8E08-05EB69DD99B7}.Release|x64.ActiveCfg = Release|Any CPU + {8EDF0733-D5DD-4D30-8E08-05EB69DD99B7}.Release|x64.Build.0 = Release|Any CPU + {8EDF0733-D5DD-4D30-8E08-05EB69DD99B7}.Release|x86.ActiveCfg = Release|Any CPU + {8EDF0733-D5DD-4D30-8E08-05EB69DD99B7}.Release|x86.Build.0 = Release|Any CPU + {1EEEF8C8-EA17-4D84-B1CE-870153C7D5DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1EEEF8C8-EA17-4D84-B1CE-870153C7D5DA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1EEEF8C8-EA17-4D84-B1CE-870153C7D5DA}.Debug|x64.ActiveCfg = Debug|Any CPU + {1EEEF8C8-EA17-4D84-B1CE-870153C7D5DA}.Debug|x64.Build.0 = Debug|Any CPU + {1EEEF8C8-EA17-4D84-B1CE-870153C7D5DA}.Debug|x86.ActiveCfg = Debug|Any CPU + {1EEEF8C8-EA17-4D84-B1CE-870153C7D5DA}.Debug|x86.Build.0 = Debug|Any CPU + {1EEEF8C8-EA17-4D84-B1CE-870153C7D5DA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1EEEF8C8-EA17-4D84-B1CE-870153C7D5DA}.Release|Any CPU.Build.0 = Release|Any CPU + {1EEEF8C8-EA17-4D84-B1CE-870153C7D5DA}.Release|x64.ActiveCfg = Release|Any CPU + {1EEEF8C8-EA17-4D84-B1CE-870153C7D5DA}.Release|x64.Build.0 = Release|Any CPU + {1EEEF8C8-EA17-4D84-B1CE-870153C7D5DA}.Release|x86.ActiveCfg = Release|Any CPU + {1EEEF8C8-EA17-4D84-B1CE-870153C7D5DA}.Release|x86.Build.0 = Release|Any CPU + {6E3190E9-49D7-4E40-A8C6-A29519E4A6FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6E3190E9-49D7-4E40-A8C6-A29519E4A6FC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6E3190E9-49D7-4E40-A8C6-A29519E4A6FC}.Debug|x64.ActiveCfg = Debug|Any CPU + {6E3190E9-49D7-4E40-A8C6-A29519E4A6FC}.Debug|x64.Build.0 = Debug|Any CPU + {6E3190E9-49D7-4E40-A8C6-A29519E4A6FC}.Debug|x86.ActiveCfg = Debug|Any CPU + {6E3190E9-49D7-4E40-A8C6-A29519E4A6FC}.Debug|x86.Build.0 = Debug|Any CPU + {6E3190E9-49D7-4E40-A8C6-A29519E4A6FC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6E3190E9-49D7-4E40-A8C6-A29519E4A6FC}.Release|Any CPU.Build.0 = Release|Any CPU + {6E3190E9-49D7-4E40-A8C6-A29519E4A6FC}.Release|x64.ActiveCfg = Release|Any CPU + {6E3190E9-49D7-4E40-A8C6-A29519E4A6FC}.Release|x64.Build.0 = Release|Any CPU + {6E3190E9-49D7-4E40-A8C6-A29519E4A6FC}.Release|x86.ActiveCfg = Release|Any CPU + {6E3190E9-49D7-4E40-A8C6-A29519E4A6FC}.Release|x86.Build.0 = Release|Any CPU + {70143EFD-F167-4D8F-A4C1-201DD00C864E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {70143EFD-F167-4D8F-A4C1-201DD00C864E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {70143EFD-F167-4D8F-A4C1-201DD00C864E}.Debug|x64.ActiveCfg = Debug|Any CPU + {70143EFD-F167-4D8F-A4C1-201DD00C864E}.Debug|x64.Build.0 = Debug|Any CPU + {70143EFD-F167-4D8F-A4C1-201DD00C864E}.Debug|x86.ActiveCfg = Debug|Any CPU + {70143EFD-F167-4D8F-A4C1-201DD00C864E}.Debug|x86.Build.0 = Debug|Any CPU + {70143EFD-F167-4D8F-A4C1-201DD00C864E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {70143EFD-F167-4D8F-A4C1-201DD00C864E}.Release|Any CPU.Build.0 = Release|Any CPU + {70143EFD-F167-4D8F-A4C1-201DD00C864E}.Release|x64.ActiveCfg = Release|Any CPU + {70143EFD-F167-4D8F-A4C1-201DD00C864E}.Release|x64.Build.0 = Release|Any CPU + {70143EFD-F167-4D8F-A4C1-201DD00C864E}.Release|x86.ActiveCfg = Release|Any CPU + {70143EFD-F167-4D8F-A4C1-201DD00C864E}.Release|x86.Build.0 = Release|Any CPU + {9036CD3D-6B45-4B2C-8F69-C6C4D98DCF7D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9036CD3D-6B45-4B2C-8F69-C6C4D98DCF7D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9036CD3D-6B45-4B2C-8F69-C6C4D98DCF7D}.Debug|x64.ActiveCfg = Debug|Any CPU + {9036CD3D-6B45-4B2C-8F69-C6C4D98DCF7D}.Debug|x64.Build.0 = Debug|Any CPU + {9036CD3D-6B45-4B2C-8F69-C6C4D98DCF7D}.Debug|x86.ActiveCfg = Debug|Any CPU + {9036CD3D-6B45-4B2C-8F69-C6C4D98DCF7D}.Debug|x86.Build.0 = Debug|Any CPU + {9036CD3D-6B45-4B2C-8F69-C6C4D98DCF7D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9036CD3D-6B45-4B2C-8F69-C6C4D98DCF7D}.Release|Any CPU.Build.0 = Release|Any CPU + {9036CD3D-6B45-4B2C-8F69-C6C4D98DCF7D}.Release|x64.ActiveCfg = Release|Any CPU + {9036CD3D-6B45-4B2C-8F69-C6C4D98DCF7D}.Release|x64.Build.0 = Release|Any CPU + {9036CD3D-6B45-4B2C-8F69-C6C4D98DCF7D}.Release|x86.ActiveCfg = Release|Any CPU + {9036CD3D-6B45-4B2C-8F69-C6C4D98DCF7D}.Release|x86.Build.0 = Release|Any CPU + {02054BB0-BBBD-45BA-8260-040126E98A8D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {02054BB0-BBBD-45BA-8260-040126E98A8D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {02054BB0-BBBD-45BA-8260-040126E98A8D}.Debug|x64.ActiveCfg = Debug|Any CPU + {02054BB0-BBBD-45BA-8260-040126E98A8D}.Debug|x64.Build.0 = Debug|Any CPU + {02054BB0-BBBD-45BA-8260-040126E98A8D}.Debug|x86.ActiveCfg = Debug|Any CPU + {02054BB0-BBBD-45BA-8260-040126E98A8D}.Debug|x86.Build.0 = Debug|Any CPU + {02054BB0-BBBD-45BA-8260-040126E98A8D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {02054BB0-BBBD-45BA-8260-040126E98A8D}.Release|Any CPU.Build.0 = Release|Any CPU + {02054BB0-BBBD-45BA-8260-040126E98A8D}.Release|x64.ActiveCfg = Release|Any CPU + {02054BB0-BBBD-45BA-8260-040126E98A8D}.Release|x64.Build.0 = Release|Any CPU + {02054BB0-BBBD-45BA-8260-040126E98A8D}.Release|x86.ActiveCfg = Release|Any CPU + {02054BB0-BBBD-45BA-8260-040126E98A8D}.Release|x86.Build.0 = Release|Any CPU + {02EFF071-DC63-4B96-9B1C-8BCAEF22BDA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {02EFF071-DC63-4B96-9B1C-8BCAEF22BDA2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {02EFF071-DC63-4B96-9B1C-8BCAEF22BDA2}.Debug|x64.ActiveCfg = Debug|Any CPU + {02EFF071-DC63-4B96-9B1C-8BCAEF22BDA2}.Debug|x64.Build.0 = Debug|Any CPU + {02EFF071-DC63-4B96-9B1C-8BCAEF22BDA2}.Debug|x86.ActiveCfg = Debug|Any CPU + {02EFF071-DC63-4B96-9B1C-8BCAEF22BDA2}.Debug|x86.Build.0 = Debug|Any CPU + {02EFF071-DC63-4B96-9B1C-8BCAEF22BDA2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {02EFF071-DC63-4B96-9B1C-8BCAEF22BDA2}.Release|Any CPU.Build.0 = Release|Any CPU + {02EFF071-DC63-4B96-9B1C-8BCAEF22BDA2}.Release|x64.ActiveCfg = Release|Any CPU + {02EFF071-DC63-4B96-9B1C-8BCAEF22BDA2}.Release|x64.Build.0 = Release|Any CPU + {02EFF071-DC63-4B96-9B1C-8BCAEF22BDA2}.Release|x86.ActiveCfg = Release|Any CPU + {02EFF071-DC63-4B96-9B1C-8BCAEF22BDA2}.Release|x86.Build.0 = Release|Any CPU + {3605D881-E511-46E4-B80B-5BFF98DA8A9C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3605D881-E511-46E4-B80B-5BFF98DA8A9C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3605D881-E511-46E4-B80B-5BFF98DA8A9C}.Debug|x64.ActiveCfg = Debug|Any CPU + {3605D881-E511-46E4-B80B-5BFF98DA8A9C}.Debug|x64.Build.0 = Debug|Any CPU + {3605D881-E511-46E4-B80B-5BFF98DA8A9C}.Debug|x86.ActiveCfg = Debug|Any CPU + {3605D881-E511-46E4-B80B-5BFF98DA8A9C}.Debug|x86.Build.0 = Debug|Any CPU + {3605D881-E511-46E4-B80B-5BFF98DA8A9C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3605D881-E511-46E4-B80B-5BFF98DA8A9C}.Release|Any CPU.Build.0 = Release|Any CPU + {3605D881-E511-46E4-B80B-5BFF98DA8A9C}.Release|x64.ActiveCfg = Release|Any CPU + {3605D881-E511-46E4-B80B-5BFF98DA8A9C}.Release|x64.Build.0 = Release|Any CPU + {3605D881-E511-46E4-B80B-5BFF98DA8A9C}.Release|x86.ActiveCfg = Release|Any CPU + {3605D881-E511-46E4-B80B-5BFF98DA8A9C}.Release|x86.Build.0 = Release|Any CPU + {3293A32D-36DF-4A8A-99F5-E35E86B48F45}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3293A32D-36DF-4A8A-99F5-E35E86B48F45}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3293A32D-36DF-4A8A-99F5-E35E86B48F45}.Debug|x64.ActiveCfg = Debug|Any CPU + {3293A32D-36DF-4A8A-99F5-E35E86B48F45}.Debug|x64.Build.0 = Debug|Any CPU + {3293A32D-36DF-4A8A-99F5-E35E86B48F45}.Debug|x86.ActiveCfg = Debug|Any CPU + {3293A32D-36DF-4A8A-99F5-E35E86B48F45}.Debug|x86.Build.0 = Debug|Any CPU + {3293A32D-36DF-4A8A-99F5-E35E86B48F45}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3293A32D-36DF-4A8A-99F5-E35E86B48F45}.Release|Any CPU.Build.0 = Release|Any CPU + {3293A32D-36DF-4A8A-99F5-E35E86B48F45}.Release|x64.ActiveCfg = Release|Any CPU + {3293A32D-36DF-4A8A-99F5-E35E86B48F45}.Release|x64.Build.0 = Release|Any CPU + {3293A32D-36DF-4A8A-99F5-E35E86B48F45}.Release|x86.ActiveCfg = Release|Any CPU + {3293A32D-36DF-4A8A-99F5-E35E86B48F45}.Release|x86.Build.0 = Release|Any CPU + {E0F4A65D-F0BB-4EED-ADE8-B514E0F82971}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E0F4A65D-F0BB-4EED-ADE8-B514E0F82971}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E0F4A65D-F0BB-4EED-ADE8-B514E0F82971}.Debug|x64.ActiveCfg = Debug|Any CPU + {E0F4A65D-F0BB-4EED-ADE8-B514E0F82971}.Debug|x64.Build.0 = Debug|Any CPU + {E0F4A65D-F0BB-4EED-ADE8-B514E0F82971}.Debug|x86.ActiveCfg = Debug|Any CPU + {E0F4A65D-F0BB-4EED-ADE8-B514E0F82971}.Debug|x86.Build.0 = Debug|Any CPU + {E0F4A65D-F0BB-4EED-ADE8-B514E0F82971}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E0F4A65D-F0BB-4EED-ADE8-B514E0F82971}.Release|Any CPU.Build.0 = Release|Any CPU + {E0F4A65D-F0BB-4EED-ADE8-B514E0F82971}.Release|x64.ActiveCfg = Release|Any CPU + {E0F4A65D-F0BB-4EED-ADE8-B514E0F82971}.Release|x64.Build.0 = Release|Any CPU + {E0F4A65D-F0BB-4EED-ADE8-B514E0F82971}.Release|x86.ActiveCfg = Release|Any CPU + {E0F4A65D-F0BB-4EED-ADE8-B514E0F82971}.Release|x86.Build.0 = Release|Any CPU + {92113D6B-04C3-456C-867B-87DDF02A796A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {92113D6B-04C3-456C-867B-87DDF02A796A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {92113D6B-04C3-456C-867B-87DDF02A796A}.Debug|x64.ActiveCfg = Debug|Any CPU + {92113D6B-04C3-456C-867B-87DDF02A796A}.Debug|x64.Build.0 = Debug|Any CPU + {92113D6B-04C3-456C-867B-87DDF02A796A}.Debug|x86.ActiveCfg = Debug|Any CPU + {92113D6B-04C3-456C-867B-87DDF02A796A}.Debug|x86.Build.0 = Debug|Any CPU + {92113D6B-04C3-456C-867B-87DDF02A796A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {92113D6B-04C3-456C-867B-87DDF02A796A}.Release|Any CPU.Build.0 = Release|Any CPU + {92113D6B-04C3-456C-867B-87DDF02A796A}.Release|x64.ActiveCfg = Release|Any CPU + {92113D6B-04C3-456C-867B-87DDF02A796A}.Release|x64.Build.0 = Release|Any CPU + {92113D6B-04C3-456C-867B-87DDF02A796A}.Release|x86.ActiveCfg = Release|Any CPU + {92113D6B-04C3-456C-867B-87DDF02A796A}.Release|x86.Build.0 = Release|Any CPU + {86002AE6-8317-4451-A649-8E95AC5148F6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {86002AE6-8317-4451-A649-8E95AC5148F6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {86002AE6-8317-4451-A649-8E95AC5148F6}.Debug|x64.ActiveCfg = Debug|Any CPU + {86002AE6-8317-4451-A649-8E95AC5148F6}.Debug|x64.Build.0 = Debug|Any CPU + {86002AE6-8317-4451-A649-8E95AC5148F6}.Debug|x86.ActiveCfg = Debug|Any CPU + {86002AE6-8317-4451-A649-8E95AC5148F6}.Debug|x86.Build.0 = Debug|Any CPU + {86002AE6-8317-4451-A649-8E95AC5148F6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {86002AE6-8317-4451-A649-8E95AC5148F6}.Release|Any CPU.Build.0 = Release|Any CPU + {86002AE6-8317-4451-A649-8E95AC5148F6}.Release|x64.ActiveCfg = Release|Any CPU + {86002AE6-8317-4451-A649-8E95AC5148F6}.Release|x64.Build.0 = Release|Any CPU + {86002AE6-8317-4451-A649-8E95AC5148F6}.Release|x86.ActiveCfg = Release|Any CPU + {86002AE6-8317-4451-A649-8E95AC5148F6}.Release|x86.Build.0 = Release|Any CPU + {8997D5A8-097E-46F9-9B99-D9A367A1B1EE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8997D5A8-097E-46F9-9B99-D9A367A1B1EE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8997D5A8-097E-46F9-9B99-D9A367A1B1EE}.Debug|x64.ActiveCfg = Debug|Any CPU + {8997D5A8-097E-46F9-9B99-D9A367A1B1EE}.Debug|x64.Build.0 = Debug|Any CPU + {8997D5A8-097E-46F9-9B99-D9A367A1B1EE}.Debug|x86.ActiveCfg = Debug|Any CPU + {8997D5A8-097E-46F9-9B99-D9A367A1B1EE}.Debug|x86.Build.0 = Debug|Any CPU + {8997D5A8-097E-46F9-9B99-D9A367A1B1EE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8997D5A8-097E-46F9-9B99-D9A367A1B1EE}.Release|Any CPU.Build.0 = Release|Any CPU + {8997D5A8-097E-46F9-9B99-D9A367A1B1EE}.Release|x64.ActiveCfg = Release|Any CPU + {8997D5A8-097E-46F9-9B99-D9A367A1B1EE}.Release|x64.Build.0 = Release|Any CPU + {8997D5A8-097E-46F9-9B99-D9A367A1B1EE}.Release|x86.ActiveCfg = Release|Any CPU + {8997D5A8-097E-46F9-9B99-D9A367A1B1EE}.Release|x86.Build.0 = Release|Any CPU + {98F9E296-DB25-4EFB-AB0F-549602F8FC16}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {98F9E296-DB25-4EFB-AB0F-549602F8FC16}.Debug|Any CPU.Build.0 = Debug|Any CPU + {98F9E296-DB25-4EFB-AB0F-549602F8FC16}.Debug|x64.ActiveCfg = Debug|Any CPU + {98F9E296-DB25-4EFB-AB0F-549602F8FC16}.Debug|x64.Build.0 = Debug|Any CPU + {98F9E296-DB25-4EFB-AB0F-549602F8FC16}.Debug|x86.ActiveCfg = Debug|Any CPU + {98F9E296-DB25-4EFB-AB0F-549602F8FC16}.Debug|x86.Build.0 = Debug|Any CPU + {98F9E296-DB25-4EFB-AB0F-549602F8FC16}.Release|Any CPU.ActiveCfg = Release|Any CPU + {98F9E296-DB25-4EFB-AB0F-549602F8FC16}.Release|Any CPU.Build.0 = Release|Any CPU + {98F9E296-DB25-4EFB-AB0F-549602F8FC16}.Release|x64.ActiveCfg = Release|Any CPU + {98F9E296-DB25-4EFB-AB0F-549602F8FC16}.Release|x64.Build.0 = Release|Any CPU + {98F9E296-DB25-4EFB-AB0F-549602F8FC16}.Release|x86.ActiveCfg = Release|Any CPU + {98F9E296-DB25-4EFB-AB0F-549602F8FC16}.Release|x86.Build.0 = Release|Any CPU + {8E9F474B-D58C-49C4-8EDB-8A9BDBA3F98A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8E9F474B-D58C-49C4-8EDB-8A9BDBA3F98A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8E9F474B-D58C-49C4-8EDB-8A9BDBA3F98A}.Debug|x64.ActiveCfg = Debug|Any CPU + {8E9F474B-D58C-49C4-8EDB-8A9BDBA3F98A}.Debug|x64.Build.0 = Debug|Any CPU + {8E9F474B-D58C-49C4-8EDB-8A9BDBA3F98A}.Debug|x86.ActiveCfg = Debug|Any CPU + {8E9F474B-D58C-49C4-8EDB-8A9BDBA3F98A}.Debug|x86.Build.0 = Debug|Any CPU + {8E9F474B-D58C-49C4-8EDB-8A9BDBA3F98A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8E9F474B-D58C-49C4-8EDB-8A9BDBA3F98A}.Release|Any CPU.Build.0 = Release|Any CPU + {8E9F474B-D58C-49C4-8EDB-8A9BDBA3F98A}.Release|x64.ActiveCfg = Release|Any CPU + {8E9F474B-D58C-49C4-8EDB-8A9BDBA3F98A}.Release|x64.Build.0 = Release|Any CPU + {8E9F474B-D58C-49C4-8EDB-8A9BDBA3F98A}.Release|x86.ActiveCfg = Release|Any CPU + {8E9F474B-D58C-49C4-8EDB-8A9BDBA3F98A}.Release|x86.Build.0 = Release|Any CPU + {FB0DA201-C124-4DE6-AFCD-7996C2C05BD0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FB0DA201-C124-4DE6-AFCD-7996C2C05BD0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FB0DA201-C124-4DE6-AFCD-7996C2C05BD0}.Debug|x64.ActiveCfg = Debug|Any CPU + {FB0DA201-C124-4DE6-AFCD-7996C2C05BD0}.Debug|x64.Build.0 = Debug|Any CPU + {FB0DA201-C124-4DE6-AFCD-7996C2C05BD0}.Debug|x86.ActiveCfg = Debug|Any CPU + {FB0DA201-C124-4DE6-AFCD-7996C2C05BD0}.Debug|x86.Build.0 = Debug|Any CPU + {FB0DA201-C124-4DE6-AFCD-7996C2C05BD0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FB0DA201-C124-4DE6-AFCD-7996C2C05BD0}.Release|Any CPU.Build.0 = Release|Any CPU + {FB0DA201-C124-4DE6-AFCD-7996C2C05BD0}.Release|x64.ActiveCfg = Release|Any CPU + {FB0DA201-C124-4DE6-AFCD-7996C2C05BD0}.Release|x64.Build.0 = Release|Any CPU + {FB0DA201-C124-4DE6-AFCD-7996C2C05BD0}.Release|x86.ActiveCfg = Release|Any CPU + {FB0DA201-C124-4DE6-AFCD-7996C2C05BD0}.Release|x86.Build.0 = Release|Any CPU + {D117C434-D16D-4E38-A8B7-4663944CE167}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D117C434-D16D-4E38-A8B7-4663944CE167}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D117C434-D16D-4E38-A8B7-4663944CE167}.Debug|x64.ActiveCfg = Debug|Any CPU + {D117C434-D16D-4E38-A8B7-4663944CE167}.Debug|x64.Build.0 = Debug|Any CPU + {D117C434-D16D-4E38-A8B7-4663944CE167}.Debug|x86.ActiveCfg = Debug|Any CPU + {D117C434-D16D-4E38-A8B7-4663944CE167}.Debug|x86.Build.0 = Debug|Any CPU + {D117C434-D16D-4E38-A8B7-4663944CE167}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D117C434-D16D-4E38-A8B7-4663944CE167}.Release|Any CPU.Build.0 = Release|Any CPU + {D117C434-D16D-4E38-A8B7-4663944CE167}.Release|x64.ActiveCfg = Release|Any CPU + {D117C434-D16D-4E38-A8B7-4663944CE167}.Release|x64.Build.0 = Release|Any CPU + {D117C434-D16D-4E38-A8B7-4663944CE167}.Release|x86.ActiveCfg = Release|Any CPU + {D117C434-D16D-4E38-A8B7-4663944CE167}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {549D1333-970B-4C0B-80E1-E96C910A4DBD} = {8AD7BBC4-892F-4F45-A239-622DA6C181ED} + {53E70BA4-4B34-43A4-B6F9-9BEC482650AD} = {8AD7BBC4-892F-4F45-A239-622DA6C181ED} + {0A500F50-2CA6-4FD1-B01D-F4E1D33CCCC9} = {8AD7BBC4-892F-4F45-A239-622DA6C181ED} + {814B9486-A590-4C70-A323-3C1118DB5AA2} = {BE77AC33-F34A-41B4-A22F-DB45A4B8E49C} + {669396CA-E180-4536-BB9D-565DF522964B} = {BE77AC33-F34A-41B4-A22F-DB45A4B8E49C} + {0BD0C661-CEDD-4D64-BAC8-3947D9AD21F2} = {BE77AC33-F34A-41B4-A22F-DB45A4B8E49C} + {D4C040D5-598E-43DB-8341-B1E14368DBE2} = {0BD0C661-CEDD-4D64-BAC8-3947D9AD21F2} + {EF440F94-84ED-43DB-8D8B-671B1F345B84} = {0BD0C661-CEDD-4D64-BAC8-3947D9AD21F2} + {C5AE51C7-47CD-489C-80CD-799209DAA0E5} = {0BD0C661-CEDD-4D64-BAC8-3947D9AD21F2} + {92B77A61-B60C-4F4E-96FF-C34BEEAD2D54} = {0BD0C661-CEDD-4D64-BAC8-3947D9AD21F2} + {DD96E545-2466-4531-8F3A-D588871A4D19} = {0B6A1C60-596A-45A8-A71E-940F463F5C0D} + {8EDF0733-D5DD-4D30-8E08-05EB69DD99B7} = {4FD7794A-3AB7-4455-9EA6-392CEE415588} + {1EEEF8C8-EA17-4D84-B1CE-870153C7D5DA} = {4FD7794A-3AB7-4455-9EA6-392CEE415588} + {6E3190E9-49D7-4E40-A8C6-A29519E4A6FC} = {6D83D4EC-451D-40B9-BF80-475667CC5DFE} + {70143EFD-F167-4D8F-A4C1-201DD00C864E} = {3BCD0E35-4CBA-4A14-80D8-9D695F14A384} + {9036CD3D-6B45-4B2C-8F69-C6C4D98DCF7D} = {185140F7-1F8F-430F-BC47-63C2712AC67F} + {02054BB0-BBBD-45BA-8260-040126E98A8D} = {185140F7-1F8F-430F-BC47-63C2712AC67F} + {02EFF071-DC63-4B96-9B1C-8BCAEF22BDA2} = {185140F7-1F8F-430F-BC47-63C2712AC67F} + {3605D881-E511-46E4-B80B-5BFF98DA8A9C} = {185140F7-1F8F-430F-BC47-63C2712AC67F} + {3293A32D-36DF-4A8A-99F5-E35E86B48F45} = {185140F7-1F8F-430F-BC47-63C2712AC67F} + {E0F4A65D-F0BB-4EED-ADE8-B514E0F82971} = {BD3AE379-14B5-4ABD-AF0E-023715D9726F} + {92113D6B-04C3-456C-867B-87DDF02A796A} = {BD3AE379-14B5-4ABD-AF0E-023715D9726F} + EndGlobalSection +EndGlobal diff --git a/src/Components/Blazor/Blazor/ref/Microsoft.AspNetCore.Blazor.csproj b/src/Components/Blazor/Blazor/ref/Microsoft.AspNetCore.Blazor.csproj index 25d2991601..57dee19888 100644 --- a/src/Components/Blazor/Blazor/ref/Microsoft.AspNetCore.Blazor.csproj +++ b/src/Components/Blazor/Blazor/ref/Microsoft.AspNetCore.Blazor.csproj @@ -2,6 +2,7 @@ netstandard2.1 + $(NoWarn);BL0006 diff --git a/src/Components/Blazor/Blazor/src/Microsoft.AspNetCore.Blazor.csproj b/src/Components/Blazor/Blazor/src/Microsoft.AspNetCore.Blazor.csproj index ff30d9d9c8..a4f7e14ee9 100644 --- a/src/Components/Blazor/Blazor/src/Microsoft.AspNetCore.Blazor.csproj +++ b/src/Components/Blazor/Blazor/src/Microsoft.AspNetCore.Blazor.csproj @@ -4,6 +4,7 @@ netstandard2.1 Build client-side single-page applications (SPAs) with Blazor running under WebAssembly. true + $(NoWarn);BL0006 diff --git a/src/Components/Blazor/Build/test/Microsoft.AspNetCore.Blazor.Build.Tests.csproj b/src/Components/Blazor/Build/test/Microsoft.AspNetCore.Blazor.Build.Tests.csproj index 652888d604..678d05098a 100644 --- a/src/Components/Blazor/Build/test/Microsoft.AspNetCore.Blazor.Build.Tests.csproj +++ b/src/Components/Blazor/Build/test/Microsoft.AspNetCore.Blazor.Build.Tests.csproj @@ -5,6 +5,7 @@ $(DefaultItemExcludes);TestFiles\**\* + $(NoWarn);BL0006 diff --git a/src/Components/Blazor/Directory.Build.props b/src/Components/Blazor/Directory.Build.props index 8df2e791dd..cf13978090 100644 --- a/src/Components/Blazor/Directory.Build.props +++ b/src/Components/Blazor/Directory.Build.props @@ -1,10 +1,4 @@ - - - - 3.1.0 - diff --git a/src/Components/Blazor/Templates/.gitignore b/src/Components/Blazor/Templates/.gitignore deleted file mode 100644 index 6216d1eae6..0000000000 --- a/src/Components/Blazor/Templates/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# We only track the .template.config.src items in source control -# The .template.config files are generated on build -src/content/**/.template.config/ diff --git a/src/Components/Components.sln b/src/Components/Components.sln deleted file mode 100644 index c88695cf66..0000000000 --- a/src/Components/Components.sln +++ /dev/null @@ -1,1671 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.28509.92 -MinimumVisualStudioVersion = 16.0.0.0 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Analyzers", "Analyzers", "{E059A46B-56E3-41E2-83F4-B5D180056F3B}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Components.Analyzers", "Analyzers\src\Microsoft.AspNetCore.Components.Analyzers.csproj", "{ECE91401-329E-4615-8684-8E910D2741C4}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Components.Analyzers.Tests", "Analyzers\test\Microsoft.AspNetCore.Components.Analyzers.Tests.csproj", "{F000C49D-3857-42A4-918D-DA4C08691FE2}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Blazor", "Blazor", "{7260DED9-22A9-4E9D-92F4-5E8A4404DEAF}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Blazor", "Blazor\Blazor\src\Microsoft.AspNetCore.Blazor.csproj", "{641922CD-E6F5-41E7-A085-EE07C2A7328D}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Blazor.Tests", "Blazor\Blazor\test\Microsoft.AspNetCore.Blazor.Tests.csproj", "{958AD6D2-174B-4B5B-BEFC-FA64B5159334}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Blazor.Build", "Blazor\Build\src\Microsoft.AspNetCore.Blazor.Build.csproj", "{E8AD67A4-77D3-4B85-AE19-4711388B62B1}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Blazor.Build.Tests", "Blazor\Build\test\Microsoft.AspNetCore.Blazor.Build.Tests.csproj", "{E38FDBB0-08C1-444E-A449-69C8A59D721B}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Blazor.DevServer", "Blazor\DevServer\src\Microsoft.AspNetCore.Blazor.DevServer.csproj", "{A6C8050D-7C18-4585-ADCF-833AC1765847}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Blazor.Server", "Blazor\Server\src\Microsoft.AspNetCore.Blazor.Server.csproj", "{A4859630-F9F7-4F5C-9FF3-6C013D7C58FA}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "testassets", "testassets", "{A7ABAC29-F73F-456D-AE54-46842CFC2E10}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HostedInAspNet.Client", "Blazor\testassets\HostedInAspNet.Client\HostedInAspNet.Client.csproj", "{FD37F740-A654-4117-BFB6-9112CE4C1D3B}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HostedInAspNet.Server", "Blazor\testassets\HostedInAspNet.Server\HostedInAspNet.Server.csproj", "{C1E2C117-BE47-4E29-94B3-753262D97A5C}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MonoSanity", "Blazor\testassets\MonoSanity\MonoSanity.csproj", "{F16C1A7C-A2BD-4EB1-8BC8-23B1375F3B9E}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MonoSanityClient", "Blazor\testassets\MonoSanityClient\MonoSanityClient.csproj", "{1C4BF2D3-44A8-4A71-B031-15B983663CB0}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StandaloneApp", "Blazor\testassets\StandaloneApp\StandaloneApp.csproj", "{C0FFB29E-4696-4875-9039-E5FA1AC5A42A}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Web", "Web", "{A27FF193-195B-4474-8E6C-840B2E339373}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Components.Web", "Web\src\Microsoft.AspNetCore.Components.Web.csproj", "{3B1A56F8-B3E0-4F33-A717-50BDD4FBE12E}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Components", "Components", "{3D9B9B2C-E379-41BD-83D4-2E099FBDA107}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Components.Performance", "Components\perf\Microsoft.AspNetCore.Components.Performance.csproj", "{35A8AE1D-ED82-485E-A8E6-A357B3CB31B3}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Components", "Components\src\Microsoft.AspNetCore.Components.csproj", "{8D49A92D-B4AA-4A5C-99C1-B4DCBD5491DD}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Components.Tests", "Components\test\Microsoft.AspNetCore.Components.Tests.csproj", "{C987E45D-53AE-49EB-BD22-A15789B12F7F}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Server", "Server", "{3A423375-4610-4366-B9D5-C2B29A53C50D}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Components.Server", "Server\src\Microsoft.AspNetCore.Components.Server.csproj", "{8D09F716-F010-4332-AB98-22246C0FE8AA}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Components.Server.Tests", "Server\test\Microsoft.AspNetCore.Components.Server.Tests.csproj", "{FE32E389-1868-4AA2-9E47-0FC823C25106}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{E9E9CF3C-CE9B-4282-B2BB-97EFC3872798}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Components.E2ETests", "test\E2ETest\Microsoft.AspNetCore.Components.E2ETests.csproj", "{B998B96D-E3CD-440E-9BFD-8F4EDC9D6732}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "testassets", "testassets", "{44E0D4F3-4430-4175-B482-0D1AEE4BB699}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BasicTestApp", "test\testassets\BasicTestApp\BasicTestApp.csproj", "{4C5AB32A-3C7E-4A55-96A7-1F5248CFE929}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestContentPackage", "test\testassets\TestContentPackage\TestContentPackage.csproj", "{423CCF23-C0B4-4D21-896C-16DC98689DB5}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Components.TestServer", "test\testassets\TestServer\Components.TestServer.csproj", "{D6AEB328-EBC0-40B1-8936-301597883DFA}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Antiforgery", "..\Antiforgery\src\Microsoft.AspNetCore.Antiforgery.csproj", "{6BA2DCAA-CB68-4AE2-BBBE-746A728D30E0}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.DataProtection.Abstractions", "..\DataProtection\Abstractions\src\Microsoft.AspNetCore.DataProtection.Abstractions.csproj", "{766CB6A1-0507-4367-A6CC-9C2EC6A39732}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Cryptography.Internal", "..\DataProtection\Cryptography.Internal\src\Microsoft.AspNetCore.Cryptography.Internal.csproj", "{992288A5-6E70-4F2D-99A6-03439BF7A5E3}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.DataProtection", "..\DataProtection\DataProtection\src\Microsoft.AspNetCore.DataProtection.csproj", "{27A226BA-C94A-4E99-897D-EDFB856CCCB5}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore", "..\DefaultBuilder\src\Microsoft.AspNetCore.csproj", "{443DBEC1-9620-4287-A8E7-DFE46A227BE6}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Hosting.Abstractions", "..\Hosting\Abstractions\src\Microsoft.AspNetCore.Hosting.Abstractions.csproj", "{C3A07F30-F2EA-4A9C-8A83-8C0BC8144863}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Hosting", "..\Hosting\Hosting\src\Microsoft.AspNetCore.Hosting.csproj", "{3A25A675-8867-420A-8921-4B6D617EBE2F}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Hosting.Server.Abstractions", "..\Hosting\Server.Abstractions\src\Microsoft.AspNetCore.Hosting.Server.Abstractions.csproj", "{B25439E1-C944-4FE1-8678-AC9E866AC4EA}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Html.Abstractions", "..\Html\Abstractions\src\Microsoft.AspNetCore.Html.Abstractions.csproj", "{214B9F12-BF3F-430F-85BC-98C6CFFFE5F8}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Authentication.Abstractions", "..\Http\Authentication.Abstractions\src\Microsoft.AspNetCore.Authentication.Abstractions.csproj", "{574F245D-ED2E-4B5F-9929-8E8377412E6D}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Authentication.Core", "..\Http\Authentication.Core\src\Microsoft.AspNetCore.Authentication.Core.csproj", "{7BE4D31D-D31F-422E-8C54-39B91A9A4DE4}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Net.Http.Headers", "..\Http\Headers\src\Microsoft.Net.Http.Headers.csproj", "{8EF63B6F-A1D9-469B-9A50-DE1613ED47A5}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Http.Abstractions", "..\Http\Http.Abstractions\src\Microsoft.AspNetCore.Http.Abstractions.csproj", "{A9291B4E-7049-4574-AC45-8D642AD3D9B0}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Http.Extensions", "..\Http\Http.Extensions\src\Microsoft.AspNetCore.Http.Extensions.csproj", "{6B847B89-DEFB-478C-B0D8-0F309602A0C5}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Http.Features", "..\Http\Http.Features\src\Microsoft.AspNetCore.Http.Features.csproj", "{3D316CA9-55C6-4D72-A408-382935555361}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Http", "..\Http\Http\src\Microsoft.AspNetCore.Http.csproj", "{E0EDCB3C-C93B-4368-9289-035D7D35382B}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Routing.Abstractions", "..\Http\Routing.Abstractions\src\Microsoft.AspNetCore.Routing.Abstractions.csproj", "{3C001B2F-2A04-478C-8A7A-1D121E8A4BB1}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Routing", "..\Http\Routing\src\Microsoft.AspNetCore.Routing.csproj", "{FF3A5823-43F0-4C98-87C4-3C5973F3C7D7}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.WebUtilities", "..\Http\WebUtilities\src\Microsoft.AspNetCore.WebUtilities.csproj", "{AB47EF50-D7F4-47AB-A49D-FFB8874EC9F7}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Cors", "..\Middleware\CORS\src\Microsoft.AspNetCore.Cors.csproj", "{8C18A50B-EAEE-4CE0-8FFC-0957FD6B5DFD}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Diagnostics.Abstractions", "..\Middleware\Diagnostics.Abstractions\src\Microsoft.AspNetCore.Diagnostics.Abstractions.csproj", "{6F46EE1F-5A3A-4D16-94C4-6CF7147BC75B}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Diagnostics", "..\Middleware\Diagnostics\src\Microsoft.AspNetCore.Diagnostics.csproj", "{EF6E0BF5-F018-4C76-A7E8-EF52D2C7D9C1}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.HostFiltering", "..\Middleware\HostFiltering\src\Microsoft.AspNetCore.HostFiltering.csproj", "{697B279A-8BC0-49C2-A57F-667E9AD81E9A}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.HttpOverrides", "..\Middleware\HttpOverrides\src\Microsoft.AspNetCore.HttpOverrides.csproj", "{F94690E9-258C-4C10-AC26-FA31F6EB9D35}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Localization", "..\Middleware\Localization\src\Microsoft.AspNetCore.Localization.csproj", "{A2AB7E2D-0FE2-4740-95E7-CE600CBD4F44}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.NodeServices", "..\Middleware\NodeServices\src\Microsoft.AspNetCore.NodeServices.csproj", "{71209D14-8469-40FB-B052-8308AF22A0EC}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.ResponseCaching.Abstractions", "..\Middleware\ResponseCaching.Abstractions\src\Microsoft.AspNetCore.ResponseCaching.Abstractions.csproj", "{86CBF0C9-76C8-4084-9758-E36731AEC1D7}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.ResponseCompression", "..\Middleware\ResponseCompression\src\Microsoft.AspNetCore.ResponseCompression.csproj", "{EA169B0E-3F8C-4436-82F4-56768263D256}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.SpaServices.Extensions", "..\Middleware\SpaServices.Extensions\src\Microsoft.AspNetCore.SpaServices.Extensions.csproj", "{1CDF7EC6-A25A-44BC-8CD3-C9F6AD13CF0B}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.SpaServices", "..\Middleware\SpaServices\src\Microsoft.AspNetCore.SpaServices.csproj", "{5AEEAA34-01A0-418D-A8D0-E89A5B9A0EF1}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.StaticFiles", "..\Middleware\StaticFiles\src\Microsoft.AspNetCore.StaticFiles.csproj", "{BBDB70EB-2C08-43E7-8D82-BEE18C8881C8}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.WebSockets", "..\Middleware\WebSockets\src\Microsoft.AspNetCore.WebSockets.csproj", "{AB827016-9D0A-4443-BFF0-80CB9E947D39}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Mvc.Abstractions", "..\Mvc\Mvc.Abstractions\src\Microsoft.AspNetCore.Mvc.Abstractions.csproj", "{707BB7F9-3E71-4364-8AD0-949735B5D33C}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Mvc.Analyzers", "..\Mvc\Mvc.Analyzers\src\Microsoft.AspNetCore.Mvc.Analyzers.csproj", "{E09006B7-2022-43CD-A0D9-127282F95A57}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Mvc.ApiExplorer", "..\Mvc\Mvc.ApiExplorer\src\Microsoft.AspNetCore.Mvc.ApiExplorer.csproj", "{61E8C8E2-1CF4-42DA-8822-AFEC7FA47F16}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Mvc.Core", "..\Mvc\Mvc.Core\src\Microsoft.AspNetCore.Mvc.Core.csproj", "{1F501D4D-CEA4-445B-86C9-7215A6811368}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Mvc.Cors", "..\Mvc\Mvc.Cors\src\Microsoft.AspNetCore.Mvc.Cors.csproj", "{B5037DC9-2690-42FA-8725-514E4A9EFEAD}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Mvc.DataAnnotations", "..\Mvc\Mvc.DataAnnotations\src\Microsoft.AspNetCore.Mvc.DataAnnotations.csproj", "{AC7782F2-1F03-4615-A600-A7FE0FDEC5E5}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Mvc.Localization", "..\Mvc\Mvc.Localization\src\Microsoft.AspNetCore.Mvc.Localization.csproj", "{D5C02B69-4E7B-4628-8BDA-B622A2FB2A97}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Mvc.Razor", "..\Mvc\Mvc.Razor\src\Microsoft.AspNetCore.Mvc.Razor.csproj", "{74F10D31-161F-49A4-ACD7-282211447CE4}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Mvc.RazorPages", "..\Mvc\Mvc.RazorPages\src\Microsoft.AspNetCore.Mvc.RazorPages.csproj", "{DBA8E5FE-DE74-4E24-A9A2-0FBBCC1C2792}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Mvc.TagHelpers", "..\Mvc\Mvc.TagHelpers\src\Microsoft.AspNetCore.Mvc.TagHelpers.csproj", "{2BBA2091-C991-4696-B70F-5C2D114D5674}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Mvc.ViewFeatures", "..\Mvc\Mvc.ViewFeatures\src\Microsoft.AspNetCore.Mvc.ViewFeatures.csproj", "{D9E125B3-8FFD-47CE-9C0E-FF5CEAF633AE}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Mvc", "..\Mvc\Mvc\src\Microsoft.AspNetCore.Mvc.csproj", "{DA1687B8-10E4-4F50-B074-60D20912A9BD}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Razor.Runtime", "..\Razor\Razor.Runtime\src\Microsoft.AspNetCore.Razor.Runtime.csproj", "{97CE175F-9290-479F-A6EB-EEF4C6816624}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Razor", "..\Razor\Razor\src\Microsoft.AspNetCore.Razor.csproj", "{492ADBEC-D788-4039-A544-E1510D9328C1}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Authorization", "..\Security\Authorization\Core\src\Microsoft.AspNetCore.Authorization.csproj", "{B0A51484-8A24-4B9C-996B-415EB7733D56}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Authorization.Policy", "..\Security\Authorization\Policy\src\Microsoft.AspNetCore.Authorization.Policy.csproj", "{D809A2F0-0B7B-4B5D-B70C-05EFD3203301}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Connections.Abstractions", "..\Servers\Connections.Abstractions\src\Microsoft.AspNetCore.Connections.Abstractions.csproj", "{365365A2-18A9-4EF8-A4CB-F096DAF078D9}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server.IIS", "..\Servers\IIS\IIS\src\Microsoft.AspNetCore.Server.IIS.csproj", "{92D23FF6-3C79-46CD-98ED-24DA16F8FDC3}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server.IISIntegration", "..\Servers\IIS\IISIntegration\src\Microsoft.AspNetCore.Server.IISIntegration.csproj", "{D8C72607-7E3E-4124-A065-A57F23E9F2BA}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server.Kestrel.Core", "..\Servers\Kestrel\Core\src\Microsoft.AspNetCore.Server.Kestrel.Core.csproj", "{4272499A-C424-41DF-B6B8-DF3C19416BE2}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server.Kestrel", "..\Servers\Kestrel\Kestrel\src\Microsoft.AspNetCore.Server.Kestrel.csproj", "{E01CD19E-B0BE-4480-8B8E-3701DE862E62}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets", "..\Servers\Kestrel\Transport.Sockets\src\Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.csproj", "{AA87CAA1-2456-4108-A02F-E16B9B8A98EE}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Http.Connections.Common", "..\SignalR\common\Http.Connections.Common\src\Microsoft.AspNetCore.Http.Connections.Common.csproj", "{DC2F67CC-79DD-4F7C-AFD1-AC0D12B331C9}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Http.Connections", "..\SignalR\common\Http.Connections\src\Microsoft.AspNetCore.Http.Connections.csproj", "{56DA124E-A37A-44DE-9DED-2764DDF0816C}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.SignalR.Protocols.MessagePack", "..\SignalR\common\Protocols.MessagePack\src\Microsoft.AspNetCore.SignalR.Protocols.MessagePack.csproj", "{527DB7FD-B118-4E49-B68A-55AAE9BFA109}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson", "..\SignalR\common\Protocols.NewtonsoftJson\src\Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson.csproj", "{BB6E57A6-5434-46D4-AA09-72DC29794506}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.SignalR.Common", "..\SignalR\common\SignalR.Common\src\Microsoft.AspNetCore.SignalR.Common.csproj", "{557608E1-1DF3-4A24-80EB-C557C676A9CE}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.SignalR.Core", "..\SignalR\server\Core\src\Microsoft.AspNetCore.SignalR.Core.csproj", "{9241EDB4-8FCE-4F8E-9727-C9557C59907C}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.SignalR", "..\SignalR\server\SignalR\src\Microsoft.AspNetCore.SignalR.csproj", "{3FAF725B-A628-4531-9F61-499660CD4347}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "dependencies", "dependencies", "{2FC10057-7A0A-4E34-8302-879925BC0102}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Mvc.NewtonsoftJson", "..\Mvc\Mvc.NewtonsoftJson\src\Microsoft.AspNetCore.Mvc.NewtonsoftJson.csproj", "{04262990-929C-42BF-85A9-21C25FA95617}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.JsonPatch", "..\Features\JsonPatch\src\Microsoft.AspNetCore.JsonPatch.csproj", "{DC47C40A-FC38-44E4-94A4-ADE794E76309}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{BB236B66-28C0-49DD-9CD4-C4673CD4E7B4}" - ProjectSection(SolutionItems) = preProject - ..\..\.editorconfig = ..\..\.editorconfig - EndProjectSection -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.SignalR.Protocols.Json", "..\SignalR\common\Protocols.Json\src\Microsoft.AspNetCore.SignalR.Protocols.Json.csproj", "{ED210157-461B-45BB-9D86-B81A62792C30}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.SignalR.Client", "..\SignalR\clients\csharp\Client\src\Microsoft.AspNetCore.SignalR.Client.csproj", "{DA137BD4-F7F1-4D53-855F-5EC40CEA36B0}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.SignalR.Client.Core", "..\SignalR\clients\csharp\Client.Core\src\Microsoft.AspNetCore.SignalR.Client.Core.csproj", "{0CDAB70B-71DC-43BE-ACB7-AD2EE3541FFB}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Http.Connections.Client", "..\SignalR\clients\csharp\Http.Connections.Client\src\Microsoft.AspNetCore.Http.Connections.Client.csproj", "{F88118E1-6F4A-4F89-B047-5FFD2889B9F0}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Blazor.HttpClient", "Blazor\Http\src\Microsoft.AspNetCore.Blazor.HttpClient.csproj", "{74D21785-2FAB-4266-B7C4-E311EC8EE0DF}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Blazor.HttpClient.Tests", "Blazor\Http\test\Microsoft.AspNetCore.Blazor.HttpClient.Tests.csproj", "{E4C01A3F-D3C1-4639-A6A9-930E918843DD}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Components.Web.Tests", "Web\test\Microsoft.AspNetCore.Components.Web.Tests.csproj", "{DE297C91-B3E9-4C6F-B74D-0AF9EFEBF684}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Authorization", "Authorization", "{08791FEE-761D-40EF-B701-1D31FD1E6E53}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Components.Authorization", "Authorization\src\Microsoft.AspNetCore.Components.Authorization.csproj", "{956F540A-3CDA-4913-9373-1A4E8A93BDD8}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Components.Authorization.Tests", "Authorization\test\Microsoft.AspNetCore.Components.Authorization.Tests.csproj", "{B13CDE69-ED22-4664-AAD7-686ED8CD5E88}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Forms", "Forms", "{B0EEB429-4C8C-42AA-8822-3058E7DBC98F}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Components.Forms", "Forms\src\Microsoft.AspNetCore.Components.Forms.csproj", "{A5C132FB-1E03-4DA9-8D05-80755ED1D0ED}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Components.Forms.Tests", "Forms\test\Microsoft.AspNetCore.Components.Forms.Tests.csproj", "{173D84A3-0F37-480F-AC0F-7E2DBBE32B28}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{46E4300C-5726-4108-B9A2-18BB94EB26ED}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.HttpsPolicy", "..\Middleware\HttpsPolicy\src\Microsoft.AspNetCore.HttpsPolicy.csproj", "{4664276D-606A-4BB3-873A-9EE84FB22877}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlazorServerApp", "Samples\BlazorServerApp\BlazorServerApp.csproj", "{BBF37AF9-8290-4B70-8BA8-0F6017B3B620}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Ignitor", "Ignitor", "{BDE2397D-C53A-4783-8B3A-1F54F48A6926}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ignitor", "Ignitor\src\Ignitor.csproj", "{CD0EF85C-4187-4515-A355-E5A0D4485F40}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ignitor.Test", "Ignitor\test\Ignitor.Test.csproj", "{F31E8118-014E-4CCE-8A48-5282F7B9BB3E}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Blazor.DataAnnotations.Validation", "Blazor\Validation\src\Microsoft.AspNetCore.Blazor.DataAnnotations.Validation.csproj", "{B70F90C7-2696-4050-B24E-BF0308F4E059}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Blazor.DataAnnotations.Validation.Tests", "Blazor\Validation\test\Microsoft.AspNetCore.Blazor.DataAnnotations.Validation.Tests.csproj", "{A5617A9D-C71E-44DE-936C-27611EB40A02}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Mono.WebAssembly.Interop", "Mono.WebAssembly.Interop", "{21BB9C13-20C1-4F2B-80E4-D7C64AA3BD05}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mono.WebAssembly.Interop", "Blazor\Mono.WebAssembly.Interop\src\Mono.WebAssembly.Interop.csproj", "{D141CFEE-D10A-406B-8963-F86FA13732E3}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ComponentsApp.Server", "test\testassets\ComponentsApp.Server\ComponentsApp.Server.csproj", "{F2E27E1C-2E47-42C1-9AC7-36265A381717}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "benchmarkapps", "benchmarkapps", "{CCC82E97-7B58-43E2-BBBD-23D82F926367}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Wasm.Performance", "Wasm.Performance", "{F65EFF0F-ACF3-46BD-9A8F-CDA94AF1885A}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wasm.Performance.Driver", "benchmarkapps\Wasm.Performance\Driver\Wasm.Performance.Driver.csproj", "{CA9948CA-B3FA-4C2E-A726-5E47BAD19457}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wasm.Performance.TestApp", "benchmarkapps\Wasm.Performance\TestApp\Wasm.Performance.TestApp.csproj", "{97EA0A7D-FE5E-47D1-ADDC-4BFD702F55AB}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|Any CPU = Release|Any CPU - Release|x64 = Release|x64 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {ECE91401-329E-4615-8684-8E910D2741C4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {ECE91401-329E-4615-8684-8E910D2741C4}.Debug|Any CPU.Build.0 = Debug|Any CPU - {ECE91401-329E-4615-8684-8E910D2741C4}.Debug|x64.ActiveCfg = Debug|Any CPU - {ECE91401-329E-4615-8684-8E910D2741C4}.Debug|x64.Build.0 = Debug|Any CPU - {ECE91401-329E-4615-8684-8E910D2741C4}.Debug|x86.ActiveCfg = Debug|Any CPU - {ECE91401-329E-4615-8684-8E910D2741C4}.Debug|x86.Build.0 = Debug|Any CPU - {ECE91401-329E-4615-8684-8E910D2741C4}.Release|Any CPU.ActiveCfg = Release|Any CPU - {ECE91401-329E-4615-8684-8E910D2741C4}.Release|Any CPU.Build.0 = Release|Any CPU - {ECE91401-329E-4615-8684-8E910D2741C4}.Release|x64.ActiveCfg = Release|Any CPU - {ECE91401-329E-4615-8684-8E910D2741C4}.Release|x64.Build.0 = Release|Any CPU - {ECE91401-329E-4615-8684-8E910D2741C4}.Release|x86.ActiveCfg = Release|Any CPU - {ECE91401-329E-4615-8684-8E910D2741C4}.Release|x86.Build.0 = Release|Any CPU - {F000C49D-3857-42A4-918D-DA4C08691FE2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F000C49D-3857-42A4-918D-DA4C08691FE2}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F000C49D-3857-42A4-918D-DA4C08691FE2}.Debug|x64.ActiveCfg = Debug|Any CPU - {F000C49D-3857-42A4-918D-DA4C08691FE2}.Debug|x64.Build.0 = Debug|Any CPU - {F000C49D-3857-42A4-918D-DA4C08691FE2}.Debug|x86.ActiveCfg = Debug|Any CPU - {F000C49D-3857-42A4-918D-DA4C08691FE2}.Debug|x86.Build.0 = Debug|Any CPU - {F000C49D-3857-42A4-918D-DA4C08691FE2}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F000C49D-3857-42A4-918D-DA4C08691FE2}.Release|Any CPU.Build.0 = Release|Any CPU - {F000C49D-3857-42A4-918D-DA4C08691FE2}.Release|x64.ActiveCfg = Release|Any CPU - {F000C49D-3857-42A4-918D-DA4C08691FE2}.Release|x64.Build.0 = Release|Any CPU - {F000C49D-3857-42A4-918D-DA4C08691FE2}.Release|x86.ActiveCfg = Release|Any CPU - {F000C49D-3857-42A4-918D-DA4C08691FE2}.Release|x86.Build.0 = Release|Any CPU - {641922CD-E6F5-41E7-A085-EE07C2A7328D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {641922CD-E6F5-41E7-A085-EE07C2A7328D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {641922CD-E6F5-41E7-A085-EE07C2A7328D}.Debug|x64.ActiveCfg = Debug|Any CPU - {641922CD-E6F5-41E7-A085-EE07C2A7328D}.Debug|x64.Build.0 = Debug|Any CPU - {641922CD-E6F5-41E7-A085-EE07C2A7328D}.Debug|x86.ActiveCfg = Debug|Any CPU - {641922CD-E6F5-41E7-A085-EE07C2A7328D}.Debug|x86.Build.0 = Debug|Any CPU - {641922CD-E6F5-41E7-A085-EE07C2A7328D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {641922CD-E6F5-41E7-A085-EE07C2A7328D}.Release|Any CPU.Build.0 = Release|Any CPU - {641922CD-E6F5-41E7-A085-EE07C2A7328D}.Release|x64.ActiveCfg = Release|Any CPU - {641922CD-E6F5-41E7-A085-EE07C2A7328D}.Release|x64.Build.0 = Release|Any CPU - {641922CD-E6F5-41E7-A085-EE07C2A7328D}.Release|x86.ActiveCfg = Release|Any CPU - {641922CD-E6F5-41E7-A085-EE07C2A7328D}.Release|x86.Build.0 = Release|Any CPU - {958AD6D2-174B-4B5B-BEFC-FA64B5159334}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {958AD6D2-174B-4B5B-BEFC-FA64B5159334}.Debug|Any CPU.Build.0 = Debug|Any CPU - {958AD6D2-174B-4B5B-BEFC-FA64B5159334}.Debug|x64.ActiveCfg = Debug|Any CPU - {958AD6D2-174B-4B5B-BEFC-FA64B5159334}.Debug|x64.Build.0 = Debug|Any CPU - {958AD6D2-174B-4B5B-BEFC-FA64B5159334}.Debug|x86.ActiveCfg = Debug|Any CPU - {958AD6D2-174B-4B5B-BEFC-FA64B5159334}.Debug|x86.Build.0 = Debug|Any CPU - {958AD6D2-174B-4B5B-BEFC-FA64B5159334}.Release|Any CPU.ActiveCfg = Release|Any CPU - {958AD6D2-174B-4B5B-BEFC-FA64B5159334}.Release|Any CPU.Build.0 = Release|Any CPU - {958AD6D2-174B-4B5B-BEFC-FA64B5159334}.Release|x64.ActiveCfg = Release|Any CPU - {958AD6D2-174B-4B5B-BEFC-FA64B5159334}.Release|x64.Build.0 = Release|Any CPU - {958AD6D2-174B-4B5B-BEFC-FA64B5159334}.Release|x86.ActiveCfg = Release|Any CPU - {958AD6D2-174B-4B5B-BEFC-FA64B5159334}.Release|x86.Build.0 = Release|Any CPU - {E8AD67A4-77D3-4B85-AE19-4711388B62B1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E8AD67A4-77D3-4B85-AE19-4711388B62B1}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E8AD67A4-77D3-4B85-AE19-4711388B62B1}.Debug|x64.ActiveCfg = Debug|Any CPU - {E8AD67A4-77D3-4B85-AE19-4711388B62B1}.Debug|x64.Build.0 = Debug|Any CPU - {E8AD67A4-77D3-4B85-AE19-4711388B62B1}.Debug|x86.ActiveCfg = Debug|Any CPU - {E8AD67A4-77D3-4B85-AE19-4711388B62B1}.Debug|x86.Build.0 = Debug|Any CPU - {E8AD67A4-77D3-4B85-AE19-4711388B62B1}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E8AD67A4-77D3-4B85-AE19-4711388B62B1}.Release|Any CPU.Build.0 = Release|Any CPU - {E8AD67A4-77D3-4B85-AE19-4711388B62B1}.Release|x64.ActiveCfg = Release|Any CPU - {E8AD67A4-77D3-4B85-AE19-4711388B62B1}.Release|x64.Build.0 = Release|Any CPU - {E8AD67A4-77D3-4B85-AE19-4711388B62B1}.Release|x86.ActiveCfg = Release|Any CPU - {E8AD67A4-77D3-4B85-AE19-4711388B62B1}.Release|x86.Build.0 = Release|Any CPU - {E38FDBB0-08C1-444E-A449-69C8A59D721B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E38FDBB0-08C1-444E-A449-69C8A59D721B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E38FDBB0-08C1-444E-A449-69C8A59D721B}.Debug|x64.ActiveCfg = Debug|Any CPU - {E38FDBB0-08C1-444E-A449-69C8A59D721B}.Debug|x64.Build.0 = Debug|Any CPU - {E38FDBB0-08C1-444E-A449-69C8A59D721B}.Debug|x86.ActiveCfg = Debug|Any CPU - {E38FDBB0-08C1-444E-A449-69C8A59D721B}.Debug|x86.Build.0 = Debug|Any CPU - {E38FDBB0-08C1-444E-A449-69C8A59D721B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E38FDBB0-08C1-444E-A449-69C8A59D721B}.Release|Any CPU.Build.0 = Release|Any CPU - {E38FDBB0-08C1-444E-A449-69C8A59D721B}.Release|x64.ActiveCfg = Release|Any CPU - {E38FDBB0-08C1-444E-A449-69C8A59D721B}.Release|x64.Build.0 = Release|Any CPU - {E38FDBB0-08C1-444E-A449-69C8A59D721B}.Release|x86.ActiveCfg = Release|Any CPU - {E38FDBB0-08C1-444E-A449-69C8A59D721B}.Release|x86.Build.0 = Release|Any CPU - {A6C8050D-7C18-4585-ADCF-833AC1765847}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A6C8050D-7C18-4585-ADCF-833AC1765847}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A6C8050D-7C18-4585-ADCF-833AC1765847}.Debug|x64.ActiveCfg = Debug|Any CPU - {A6C8050D-7C18-4585-ADCF-833AC1765847}.Debug|x64.Build.0 = Debug|Any CPU - {A6C8050D-7C18-4585-ADCF-833AC1765847}.Debug|x86.ActiveCfg = Debug|Any CPU - {A6C8050D-7C18-4585-ADCF-833AC1765847}.Debug|x86.Build.0 = Debug|Any CPU - {A6C8050D-7C18-4585-ADCF-833AC1765847}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A6C8050D-7C18-4585-ADCF-833AC1765847}.Release|Any CPU.Build.0 = Release|Any CPU - {A6C8050D-7C18-4585-ADCF-833AC1765847}.Release|x64.ActiveCfg = Release|Any CPU - {A6C8050D-7C18-4585-ADCF-833AC1765847}.Release|x64.Build.0 = Release|Any CPU - {A6C8050D-7C18-4585-ADCF-833AC1765847}.Release|x86.ActiveCfg = Release|Any CPU - {A6C8050D-7C18-4585-ADCF-833AC1765847}.Release|x86.Build.0 = Release|Any CPU - {A4859630-F9F7-4F5C-9FF3-6C013D7C58FA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A4859630-F9F7-4F5C-9FF3-6C013D7C58FA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A4859630-F9F7-4F5C-9FF3-6C013D7C58FA}.Debug|x64.ActiveCfg = Debug|Any CPU - {A4859630-F9F7-4F5C-9FF3-6C013D7C58FA}.Debug|x64.Build.0 = Debug|Any CPU - {A4859630-F9F7-4F5C-9FF3-6C013D7C58FA}.Debug|x86.ActiveCfg = Debug|Any CPU - {A4859630-F9F7-4F5C-9FF3-6C013D7C58FA}.Debug|x86.Build.0 = Debug|Any CPU - {A4859630-F9F7-4F5C-9FF3-6C013D7C58FA}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A4859630-F9F7-4F5C-9FF3-6C013D7C58FA}.Release|Any CPU.Build.0 = Release|Any CPU - {A4859630-F9F7-4F5C-9FF3-6C013D7C58FA}.Release|x64.ActiveCfg = Release|Any CPU - {A4859630-F9F7-4F5C-9FF3-6C013D7C58FA}.Release|x64.Build.0 = Release|Any CPU - {A4859630-F9F7-4F5C-9FF3-6C013D7C58FA}.Release|x86.ActiveCfg = Release|Any CPU - {A4859630-F9F7-4F5C-9FF3-6C013D7C58FA}.Release|x86.Build.0 = Release|Any CPU - {FD37F740-A654-4117-BFB6-9112CE4C1D3B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {FD37F740-A654-4117-BFB6-9112CE4C1D3B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {FD37F740-A654-4117-BFB6-9112CE4C1D3B}.Debug|x64.ActiveCfg = Debug|Any CPU - {FD37F740-A654-4117-BFB6-9112CE4C1D3B}.Debug|x64.Build.0 = Debug|Any CPU - {FD37F740-A654-4117-BFB6-9112CE4C1D3B}.Debug|x86.ActiveCfg = Debug|Any CPU - {FD37F740-A654-4117-BFB6-9112CE4C1D3B}.Debug|x86.Build.0 = Debug|Any CPU - {FD37F740-A654-4117-BFB6-9112CE4C1D3B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {FD37F740-A654-4117-BFB6-9112CE4C1D3B}.Release|Any CPU.Build.0 = Release|Any CPU - {FD37F740-A654-4117-BFB6-9112CE4C1D3B}.Release|x64.ActiveCfg = Release|Any CPU - {FD37F740-A654-4117-BFB6-9112CE4C1D3B}.Release|x64.Build.0 = Release|Any CPU - {FD37F740-A654-4117-BFB6-9112CE4C1D3B}.Release|x86.ActiveCfg = Release|Any CPU - {FD37F740-A654-4117-BFB6-9112CE4C1D3B}.Release|x86.Build.0 = Release|Any CPU - {C1E2C117-BE47-4E29-94B3-753262D97A5C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C1E2C117-BE47-4E29-94B3-753262D97A5C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C1E2C117-BE47-4E29-94B3-753262D97A5C}.Debug|x64.ActiveCfg = Debug|Any CPU - {C1E2C117-BE47-4E29-94B3-753262D97A5C}.Debug|x64.Build.0 = Debug|Any CPU - {C1E2C117-BE47-4E29-94B3-753262D97A5C}.Debug|x86.ActiveCfg = Debug|Any CPU - {C1E2C117-BE47-4E29-94B3-753262D97A5C}.Debug|x86.Build.0 = Debug|Any CPU - {C1E2C117-BE47-4E29-94B3-753262D97A5C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C1E2C117-BE47-4E29-94B3-753262D97A5C}.Release|Any CPU.Build.0 = Release|Any CPU - {C1E2C117-BE47-4E29-94B3-753262D97A5C}.Release|x64.ActiveCfg = Release|Any CPU - {C1E2C117-BE47-4E29-94B3-753262D97A5C}.Release|x64.Build.0 = Release|Any CPU - {C1E2C117-BE47-4E29-94B3-753262D97A5C}.Release|x86.ActiveCfg = Release|Any CPU - {C1E2C117-BE47-4E29-94B3-753262D97A5C}.Release|x86.Build.0 = Release|Any CPU - {F16C1A7C-A2BD-4EB1-8BC8-23B1375F3B9E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F16C1A7C-A2BD-4EB1-8BC8-23B1375F3B9E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F16C1A7C-A2BD-4EB1-8BC8-23B1375F3B9E}.Debug|x64.ActiveCfg = Debug|Any CPU - {F16C1A7C-A2BD-4EB1-8BC8-23B1375F3B9E}.Debug|x64.Build.0 = Debug|Any CPU - {F16C1A7C-A2BD-4EB1-8BC8-23B1375F3B9E}.Debug|x86.ActiveCfg = Debug|Any CPU - {F16C1A7C-A2BD-4EB1-8BC8-23B1375F3B9E}.Debug|x86.Build.0 = Debug|Any CPU - {F16C1A7C-A2BD-4EB1-8BC8-23B1375F3B9E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F16C1A7C-A2BD-4EB1-8BC8-23B1375F3B9E}.Release|Any CPU.Build.0 = Release|Any CPU - {F16C1A7C-A2BD-4EB1-8BC8-23B1375F3B9E}.Release|x64.ActiveCfg = Release|Any CPU - {F16C1A7C-A2BD-4EB1-8BC8-23B1375F3B9E}.Release|x64.Build.0 = Release|Any CPU - {F16C1A7C-A2BD-4EB1-8BC8-23B1375F3B9E}.Release|x86.ActiveCfg = Release|Any CPU - {F16C1A7C-A2BD-4EB1-8BC8-23B1375F3B9E}.Release|x86.Build.0 = Release|Any CPU - {1C4BF2D3-44A8-4A71-B031-15B983663CB0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1C4BF2D3-44A8-4A71-B031-15B983663CB0}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1C4BF2D3-44A8-4A71-B031-15B983663CB0}.Debug|x64.ActiveCfg = Debug|Any CPU - {1C4BF2D3-44A8-4A71-B031-15B983663CB0}.Debug|x64.Build.0 = Debug|Any CPU - {1C4BF2D3-44A8-4A71-B031-15B983663CB0}.Debug|x86.ActiveCfg = Debug|Any CPU - {1C4BF2D3-44A8-4A71-B031-15B983663CB0}.Debug|x86.Build.0 = Debug|Any CPU - {1C4BF2D3-44A8-4A71-B031-15B983663CB0}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1C4BF2D3-44A8-4A71-B031-15B983663CB0}.Release|Any CPU.Build.0 = Release|Any CPU - {1C4BF2D3-44A8-4A71-B031-15B983663CB0}.Release|x64.ActiveCfg = Release|Any CPU - {1C4BF2D3-44A8-4A71-B031-15B983663CB0}.Release|x64.Build.0 = Release|Any CPU - {1C4BF2D3-44A8-4A71-B031-15B983663CB0}.Release|x86.ActiveCfg = Release|Any CPU - {1C4BF2D3-44A8-4A71-B031-15B983663CB0}.Release|x86.Build.0 = Release|Any CPU - {C0FFB29E-4696-4875-9039-E5FA1AC5A42A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C0FFB29E-4696-4875-9039-E5FA1AC5A42A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C0FFB29E-4696-4875-9039-E5FA1AC5A42A}.Debug|x64.ActiveCfg = Debug|Any CPU - {C0FFB29E-4696-4875-9039-E5FA1AC5A42A}.Debug|x64.Build.0 = Debug|Any CPU - {C0FFB29E-4696-4875-9039-E5FA1AC5A42A}.Debug|x86.ActiveCfg = Debug|Any CPU - {C0FFB29E-4696-4875-9039-E5FA1AC5A42A}.Debug|x86.Build.0 = Debug|Any CPU - {C0FFB29E-4696-4875-9039-E5FA1AC5A42A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C0FFB29E-4696-4875-9039-E5FA1AC5A42A}.Release|Any CPU.Build.0 = Release|Any CPU - {C0FFB29E-4696-4875-9039-E5FA1AC5A42A}.Release|x64.ActiveCfg = Release|Any CPU - {C0FFB29E-4696-4875-9039-E5FA1AC5A42A}.Release|x64.Build.0 = Release|Any CPU - {C0FFB29E-4696-4875-9039-E5FA1AC5A42A}.Release|x86.ActiveCfg = Release|Any CPU - {C0FFB29E-4696-4875-9039-E5FA1AC5A42A}.Release|x86.Build.0 = Release|Any CPU - {3B1A56F8-B3E0-4F33-A717-50BDD4FBE12E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3B1A56F8-B3E0-4F33-A717-50BDD4FBE12E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3B1A56F8-B3E0-4F33-A717-50BDD4FBE12E}.Debug|x64.ActiveCfg = Debug|Any CPU - {3B1A56F8-B3E0-4F33-A717-50BDD4FBE12E}.Debug|x64.Build.0 = Debug|Any CPU - {3B1A56F8-B3E0-4F33-A717-50BDD4FBE12E}.Debug|x86.ActiveCfg = Debug|Any CPU - {3B1A56F8-B3E0-4F33-A717-50BDD4FBE12E}.Debug|x86.Build.0 = Debug|Any CPU - {3B1A56F8-B3E0-4F33-A717-50BDD4FBE12E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3B1A56F8-B3E0-4F33-A717-50BDD4FBE12E}.Release|Any CPU.Build.0 = Release|Any CPU - {3B1A56F8-B3E0-4F33-A717-50BDD4FBE12E}.Release|x64.ActiveCfg = Release|Any CPU - {3B1A56F8-B3E0-4F33-A717-50BDD4FBE12E}.Release|x64.Build.0 = Release|Any CPU - {3B1A56F8-B3E0-4F33-A717-50BDD4FBE12E}.Release|x86.ActiveCfg = Release|Any CPU - {3B1A56F8-B3E0-4F33-A717-50BDD4FBE12E}.Release|x86.Build.0 = Release|Any CPU - {35A8AE1D-ED82-485E-A8E6-A357B3CB31B3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {35A8AE1D-ED82-485E-A8E6-A357B3CB31B3}.Debug|Any CPU.Build.0 = Debug|Any CPU - {35A8AE1D-ED82-485E-A8E6-A357B3CB31B3}.Debug|x64.ActiveCfg = Debug|Any CPU - {35A8AE1D-ED82-485E-A8E6-A357B3CB31B3}.Debug|x64.Build.0 = Debug|Any CPU - {35A8AE1D-ED82-485E-A8E6-A357B3CB31B3}.Debug|x86.ActiveCfg = Debug|Any CPU - {35A8AE1D-ED82-485E-A8E6-A357B3CB31B3}.Debug|x86.Build.0 = Debug|Any CPU - {35A8AE1D-ED82-485E-A8E6-A357B3CB31B3}.Release|Any CPU.ActiveCfg = Release|Any CPU - {35A8AE1D-ED82-485E-A8E6-A357B3CB31B3}.Release|Any CPU.Build.0 = Release|Any CPU - {35A8AE1D-ED82-485E-A8E6-A357B3CB31B3}.Release|x64.ActiveCfg = Release|Any CPU - {35A8AE1D-ED82-485E-A8E6-A357B3CB31B3}.Release|x64.Build.0 = Release|Any CPU - {35A8AE1D-ED82-485E-A8E6-A357B3CB31B3}.Release|x86.ActiveCfg = Release|Any CPU - {35A8AE1D-ED82-485E-A8E6-A357B3CB31B3}.Release|x86.Build.0 = Release|Any CPU - {8D49A92D-B4AA-4A5C-99C1-B4DCBD5491DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8D49A92D-B4AA-4A5C-99C1-B4DCBD5491DD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8D49A92D-B4AA-4A5C-99C1-B4DCBD5491DD}.Debug|x64.ActiveCfg = Debug|Any CPU - {8D49A92D-B4AA-4A5C-99C1-B4DCBD5491DD}.Debug|x64.Build.0 = Debug|Any CPU - {8D49A92D-B4AA-4A5C-99C1-B4DCBD5491DD}.Debug|x86.ActiveCfg = Debug|Any CPU - {8D49A92D-B4AA-4A5C-99C1-B4DCBD5491DD}.Debug|x86.Build.0 = Debug|Any CPU - {8D49A92D-B4AA-4A5C-99C1-B4DCBD5491DD}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8D49A92D-B4AA-4A5C-99C1-B4DCBD5491DD}.Release|Any CPU.Build.0 = Release|Any CPU - {8D49A92D-B4AA-4A5C-99C1-B4DCBD5491DD}.Release|x64.ActiveCfg = Release|Any CPU - {8D49A92D-B4AA-4A5C-99C1-B4DCBD5491DD}.Release|x64.Build.0 = Release|Any CPU - {8D49A92D-B4AA-4A5C-99C1-B4DCBD5491DD}.Release|x86.ActiveCfg = Release|Any CPU - {8D49A92D-B4AA-4A5C-99C1-B4DCBD5491DD}.Release|x86.Build.0 = Release|Any CPU - {C987E45D-53AE-49EB-BD22-A15789B12F7F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C987E45D-53AE-49EB-BD22-A15789B12F7F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C987E45D-53AE-49EB-BD22-A15789B12F7F}.Debug|x64.ActiveCfg = Debug|Any CPU - {C987E45D-53AE-49EB-BD22-A15789B12F7F}.Debug|x64.Build.0 = Debug|Any CPU - {C987E45D-53AE-49EB-BD22-A15789B12F7F}.Debug|x86.ActiveCfg = Debug|Any CPU - {C987E45D-53AE-49EB-BD22-A15789B12F7F}.Debug|x86.Build.0 = Debug|Any CPU - {C987E45D-53AE-49EB-BD22-A15789B12F7F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C987E45D-53AE-49EB-BD22-A15789B12F7F}.Release|Any CPU.Build.0 = Release|Any CPU - {C987E45D-53AE-49EB-BD22-A15789B12F7F}.Release|x64.ActiveCfg = Release|Any CPU - {C987E45D-53AE-49EB-BD22-A15789B12F7F}.Release|x64.Build.0 = Release|Any CPU - {C987E45D-53AE-49EB-BD22-A15789B12F7F}.Release|x86.ActiveCfg = Release|Any CPU - {C987E45D-53AE-49EB-BD22-A15789B12F7F}.Release|x86.Build.0 = Release|Any CPU - {8D09F716-F010-4332-AB98-22246C0FE8AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8D09F716-F010-4332-AB98-22246C0FE8AA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8D09F716-F010-4332-AB98-22246C0FE8AA}.Debug|x64.ActiveCfg = Debug|Any CPU - {8D09F716-F010-4332-AB98-22246C0FE8AA}.Debug|x64.Build.0 = Debug|Any CPU - {8D09F716-F010-4332-AB98-22246C0FE8AA}.Debug|x86.ActiveCfg = Debug|Any CPU - {8D09F716-F010-4332-AB98-22246C0FE8AA}.Debug|x86.Build.0 = Debug|Any CPU - {8D09F716-F010-4332-AB98-22246C0FE8AA}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8D09F716-F010-4332-AB98-22246C0FE8AA}.Release|Any CPU.Build.0 = Release|Any CPU - {8D09F716-F010-4332-AB98-22246C0FE8AA}.Release|x64.ActiveCfg = Release|Any CPU - {8D09F716-F010-4332-AB98-22246C0FE8AA}.Release|x64.Build.0 = Release|Any CPU - {8D09F716-F010-4332-AB98-22246C0FE8AA}.Release|x86.ActiveCfg = Release|Any CPU - {8D09F716-F010-4332-AB98-22246C0FE8AA}.Release|x86.Build.0 = Release|Any CPU - {FE32E389-1868-4AA2-9E47-0FC823C25106}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {FE32E389-1868-4AA2-9E47-0FC823C25106}.Debug|Any CPU.Build.0 = Debug|Any CPU - {FE32E389-1868-4AA2-9E47-0FC823C25106}.Debug|x64.ActiveCfg = Debug|Any CPU - {FE32E389-1868-4AA2-9E47-0FC823C25106}.Debug|x64.Build.0 = Debug|Any CPU - {FE32E389-1868-4AA2-9E47-0FC823C25106}.Debug|x86.ActiveCfg = Debug|Any CPU - {FE32E389-1868-4AA2-9E47-0FC823C25106}.Debug|x86.Build.0 = Debug|Any CPU - {FE32E389-1868-4AA2-9E47-0FC823C25106}.Release|Any CPU.ActiveCfg = Release|Any CPU - {FE32E389-1868-4AA2-9E47-0FC823C25106}.Release|Any CPU.Build.0 = Release|Any CPU - {FE32E389-1868-4AA2-9E47-0FC823C25106}.Release|x64.ActiveCfg = Release|Any CPU - {FE32E389-1868-4AA2-9E47-0FC823C25106}.Release|x64.Build.0 = Release|Any CPU - {FE32E389-1868-4AA2-9E47-0FC823C25106}.Release|x86.ActiveCfg = Release|Any CPU - {FE32E389-1868-4AA2-9E47-0FC823C25106}.Release|x86.Build.0 = Release|Any CPU - {B998B96D-E3CD-440E-9BFD-8F4EDC9D6732}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B998B96D-E3CD-440E-9BFD-8F4EDC9D6732}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B998B96D-E3CD-440E-9BFD-8F4EDC9D6732}.Debug|x64.ActiveCfg = Debug|Any CPU - {B998B96D-E3CD-440E-9BFD-8F4EDC9D6732}.Debug|x64.Build.0 = Debug|Any CPU - {B998B96D-E3CD-440E-9BFD-8F4EDC9D6732}.Debug|x86.ActiveCfg = Debug|Any CPU - {B998B96D-E3CD-440E-9BFD-8F4EDC9D6732}.Debug|x86.Build.0 = Debug|Any CPU - {B998B96D-E3CD-440E-9BFD-8F4EDC9D6732}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B998B96D-E3CD-440E-9BFD-8F4EDC9D6732}.Release|Any CPU.Build.0 = Release|Any CPU - {B998B96D-E3CD-440E-9BFD-8F4EDC9D6732}.Release|x64.ActiveCfg = Release|Any CPU - {B998B96D-E3CD-440E-9BFD-8F4EDC9D6732}.Release|x64.Build.0 = Release|Any CPU - {B998B96D-E3CD-440E-9BFD-8F4EDC9D6732}.Release|x86.ActiveCfg = Release|Any CPU - {B998B96D-E3CD-440E-9BFD-8F4EDC9D6732}.Release|x86.Build.0 = Release|Any CPU - {4C5AB32A-3C7E-4A55-96A7-1F5248CFE929}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4C5AB32A-3C7E-4A55-96A7-1F5248CFE929}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4C5AB32A-3C7E-4A55-96A7-1F5248CFE929}.Debug|x64.ActiveCfg = Debug|Any CPU - {4C5AB32A-3C7E-4A55-96A7-1F5248CFE929}.Debug|x64.Build.0 = Debug|Any CPU - {4C5AB32A-3C7E-4A55-96A7-1F5248CFE929}.Debug|x86.ActiveCfg = Debug|Any CPU - {4C5AB32A-3C7E-4A55-96A7-1F5248CFE929}.Debug|x86.Build.0 = Debug|Any CPU - {4C5AB32A-3C7E-4A55-96A7-1F5248CFE929}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4C5AB32A-3C7E-4A55-96A7-1F5248CFE929}.Release|Any CPU.Build.0 = Release|Any CPU - {4C5AB32A-3C7E-4A55-96A7-1F5248CFE929}.Release|x64.ActiveCfg = Release|Any CPU - {4C5AB32A-3C7E-4A55-96A7-1F5248CFE929}.Release|x64.Build.0 = Release|Any CPU - {4C5AB32A-3C7E-4A55-96A7-1F5248CFE929}.Release|x86.ActiveCfg = Release|Any CPU - {4C5AB32A-3C7E-4A55-96A7-1F5248CFE929}.Release|x86.Build.0 = Release|Any CPU - {423CCF23-C0B4-4D21-896C-16DC98689DB5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {423CCF23-C0B4-4D21-896C-16DC98689DB5}.Debug|Any CPU.Build.0 = Debug|Any CPU - {423CCF23-C0B4-4D21-896C-16DC98689DB5}.Debug|x64.ActiveCfg = Debug|Any CPU - {423CCF23-C0B4-4D21-896C-16DC98689DB5}.Debug|x64.Build.0 = Debug|Any CPU - {423CCF23-C0B4-4D21-896C-16DC98689DB5}.Debug|x86.ActiveCfg = Debug|Any CPU - {423CCF23-C0B4-4D21-896C-16DC98689DB5}.Debug|x86.Build.0 = Debug|Any CPU - {423CCF23-C0B4-4D21-896C-16DC98689DB5}.Release|Any CPU.ActiveCfg = Release|Any CPU - {423CCF23-C0B4-4D21-896C-16DC98689DB5}.Release|Any CPU.Build.0 = Release|Any CPU - {423CCF23-C0B4-4D21-896C-16DC98689DB5}.Release|x64.ActiveCfg = Release|Any CPU - {423CCF23-C0B4-4D21-896C-16DC98689DB5}.Release|x64.Build.0 = Release|Any CPU - {423CCF23-C0B4-4D21-896C-16DC98689DB5}.Release|x86.ActiveCfg = Release|Any CPU - {423CCF23-C0B4-4D21-896C-16DC98689DB5}.Release|x86.Build.0 = Release|Any CPU - {D6AEB328-EBC0-40B1-8936-301597883DFA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D6AEB328-EBC0-40B1-8936-301597883DFA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D6AEB328-EBC0-40B1-8936-301597883DFA}.Debug|x64.ActiveCfg = Debug|Any CPU - {D6AEB328-EBC0-40B1-8936-301597883DFA}.Debug|x64.Build.0 = Debug|Any CPU - {D6AEB328-EBC0-40B1-8936-301597883DFA}.Debug|x86.ActiveCfg = Debug|Any CPU - {D6AEB328-EBC0-40B1-8936-301597883DFA}.Debug|x86.Build.0 = Debug|Any CPU - {D6AEB328-EBC0-40B1-8936-301597883DFA}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D6AEB328-EBC0-40B1-8936-301597883DFA}.Release|Any CPU.Build.0 = Release|Any CPU - {D6AEB328-EBC0-40B1-8936-301597883DFA}.Release|x64.ActiveCfg = Release|Any CPU - {D6AEB328-EBC0-40B1-8936-301597883DFA}.Release|x64.Build.0 = Release|Any CPU - {D6AEB328-EBC0-40B1-8936-301597883DFA}.Release|x86.ActiveCfg = Release|Any CPU - {D6AEB328-EBC0-40B1-8936-301597883DFA}.Release|x86.Build.0 = Release|Any CPU - {6BA2DCAA-CB68-4AE2-BBBE-746A728D30E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6BA2DCAA-CB68-4AE2-BBBE-746A728D30E0}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6BA2DCAA-CB68-4AE2-BBBE-746A728D30E0}.Debug|x64.ActiveCfg = Debug|Any CPU - {6BA2DCAA-CB68-4AE2-BBBE-746A728D30E0}.Debug|x64.Build.0 = Debug|Any CPU - {6BA2DCAA-CB68-4AE2-BBBE-746A728D30E0}.Debug|x86.ActiveCfg = Debug|Any CPU - {6BA2DCAA-CB68-4AE2-BBBE-746A728D30E0}.Debug|x86.Build.0 = Debug|Any CPU - {6BA2DCAA-CB68-4AE2-BBBE-746A728D30E0}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6BA2DCAA-CB68-4AE2-BBBE-746A728D30E0}.Release|Any CPU.Build.0 = Release|Any CPU - {6BA2DCAA-CB68-4AE2-BBBE-746A728D30E0}.Release|x64.ActiveCfg = Release|Any CPU - {6BA2DCAA-CB68-4AE2-BBBE-746A728D30E0}.Release|x64.Build.0 = Release|Any CPU - {6BA2DCAA-CB68-4AE2-BBBE-746A728D30E0}.Release|x86.ActiveCfg = Release|Any CPU - {6BA2DCAA-CB68-4AE2-BBBE-746A728D30E0}.Release|x86.Build.0 = Release|Any CPU - {766CB6A1-0507-4367-A6CC-9C2EC6A39732}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {766CB6A1-0507-4367-A6CC-9C2EC6A39732}.Debug|Any CPU.Build.0 = Debug|Any CPU - {766CB6A1-0507-4367-A6CC-9C2EC6A39732}.Debug|x64.ActiveCfg = Debug|Any CPU - {766CB6A1-0507-4367-A6CC-9C2EC6A39732}.Debug|x64.Build.0 = Debug|Any CPU - {766CB6A1-0507-4367-A6CC-9C2EC6A39732}.Debug|x86.ActiveCfg = Debug|Any CPU - {766CB6A1-0507-4367-A6CC-9C2EC6A39732}.Debug|x86.Build.0 = Debug|Any CPU - {766CB6A1-0507-4367-A6CC-9C2EC6A39732}.Release|Any CPU.ActiveCfg = Release|Any CPU - {766CB6A1-0507-4367-A6CC-9C2EC6A39732}.Release|Any CPU.Build.0 = Release|Any CPU - {766CB6A1-0507-4367-A6CC-9C2EC6A39732}.Release|x64.ActiveCfg = Release|Any CPU - {766CB6A1-0507-4367-A6CC-9C2EC6A39732}.Release|x64.Build.0 = Release|Any CPU - {766CB6A1-0507-4367-A6CC-9C2EC6A39732}.Release|x86.ActiveCfg = Release|Any CPU - {766CB6A1-0507-4367-A6CC-9C2EC6A39732}.Release|x86.Build.0 = Release|Any CPU - {992288A5-6E70-4F2D-99A6-03439BF7A5E3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {992288A5-6E70-4F2D-99A6-03439BF7A5E3}.Debug|Any CPU.Build.0 = Debug|Any CPU - {992288A5-6E70-4F2D-99A6-03439BF7A5E3}.Debug|x64.ActiveCfg = Debug|Any CPU - {992288A5-6E70-4F2D-99A6-03439BF7A5E3}.Debug|x64.Build.0 = Debug|Any CPU - {992288A5-6E70-4F2D-99A6-03439BF7A5E3}.Debug|x86.ActiveCfg = Debug|Any CPU - {992288A5-6E70-4F2D-99A6-03439BF7A5E3}.Debug|x86.Build.0 = Debug|Any CPU - {992288A5-6E70-4F2D-99A6-03439BF7A5E3}.Release|Any CPU.ActiveCfg = Release|Any CPU - {992288A5-6E70-4F2D-99A6-03439BF7A5E3}.Release|Any CPU.Build.0 = Release|Any CPU - {992288A5-6E70-4F2D-99A6-03439BF7A5E3}.Release|x64.ActiveCfg = Release|Any CPU - {992288A5-6E70-4F2D-99A6-03439BF7A5E3}.Release|x64.Build.0 = Release|Any CPU - {992288A5-6E70-4F2D-99A6-03439BF7A5E3}.Release|x86.ActiveCfg = Release|Any CPU - {992288A5-6E70-4F2D-99A6-03439BF7A5E3}.Release|x86.Build.0 = Release|Any CPU - {27A226BA-C94A-4E99-897D-EDFB856CCCB5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {27A226BA-C94A-4E99-897D-EDFB856CCCB5}.Debug|Any CPU.Build.0 = Debug|Any CPU - {27A226BA-C94A-4E99-897D-EDFB856CCCB5}.Debug|x64.ActiveCfg = Debug|Any CPU - {27A226BA-C94A-4E99-897D-EDFB856CCCB5}.Debug|x64.Build.0 = Debug|Any CPU - {27A226BA-C94A-4E99-897D-EDFB856CCCB5}.Debug|x86.ActiveCfg = Debug|Any CPU - {27A226BA-C94A-4E99-897D-EDFB856CCCB5}.Debug|x86.Build.0 = Debug|Any CPU - {27A226BA-C94A-4E99-897D-EDFB856CCCB5}.Release|Any CPU.ActiveCfg = Release|Any CPU - {27A226BA-C94A-4E99-897D-EDFB856CCCB5}.Release|Any CPU.Build.0 = Release|Any CPU - {27A226BA-C94A-4E99-897D-EDFB856CCCB5}.Release|x64.ActiveCfg = Release|Any CPU - {27A226BA-C94A-4E99-897D-EDFB856CCCB5}.Release|x64.Build.0 = Release|Any CPU - {27A226BA-C94A-4E99-897D-EDFB856CCCB5}.Release|x86.ActiveCfg = Release|Any CPU - {27A226BA-C94A-4E99-897D-EDFB856CCCB5}.Release|x86.Build.0 = Release|Any CPU - {443DBEC1-9620-4287-A8E7-DFE46A227BE6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {443DBEC1-9620-4287-A8E7-DFE46A227BE6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {443DBEC1-9620-4287-A8E7-DFE46A227BE6}.Debug|x64.ActiveCfg = Debug|Any CPU - {443DBEC1-9620-4287-A8E7-DFE46A227BE6}.Debug|x64.Build.0 = Debug|Any CPU - {443DBEC1-9620-4287-A8E7-DFE46A227BE6}.Debug|x86.ActiveCfg = Debug|Any CPU - {443DBEC1-9620-4287-A8E7-DFE46A227BE6}.Debug|x86.Build.0 = Debug|Any CPU - {443DBEC1-9620-4287-A8E7-DFE46A227BE6}.Release|Any CPU.ActiveCfg = Release|Any CPU - {443DBEC1-9620-4287-A8E7-DFE46A227BE6}.Release|Any CPU.Build.0 = Release|Any CPU - {443DBEC1-9620-4287-A8E7-DFE46A227BE6}.Release|x64.ActiveCfg = Release|Any CPU - {443DBEC1-9620-4287-A8E7-DFE46A227BE6}.Release|x64.Build.0 = Release|Any CPU - {443DBEC1-9620-4287-A8E7-DFE46A227BE6}.Release|x86.ActiveCfg = Release|Any CPU - {443DBEC1-9620-4287-A8E7-DFE46A227BE6}.Release|x86.Build.0 = Release|Any CPU - {C3A07F30-F2EA-4A9C-8A83-8C0BC8144863}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C3A07F30-F2EA-4A9C-8A83-8C0BC8144863}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C3A07F30-F2EA-4A9C-8A83-8C0BC8144863}.Debug|x64.ActiveCfg = Debug|Any CPU - {C3A07F30-F2EA-4A9C-8A83-8C0BC8144863}.Debug|x64.Build.0 = Debug|Any CPU - {C3A07F30-F2EA-4A9C-8A83-8C0BC8144863}.Debug|x86.ActiveCfg = Debug|Any CPU - {C3A07F30-F2EA-4A9C-8A83-8C0BC8144863}.Debug|x86.Build.0 = Debug|Any CPU - {C3A07F30-F2EA-4A9C-8A83-8C0BC8144863}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C3A07F30-F2EA-4A9C-8A83-8C0BC8144863}.Release|Any CPU.Build.0 = Release|Any CPU - {C3A07F30-F2EA-4A9C-8A83-8C0BC8144863}.Release|x64.ActiveCfg = Release|Any CPU - {C3A07F30-F2EA-4A9C-8A83-8C0BC8144863}.Release|x64.Build.0 = Release|Any CPU - {C3A07F30-F2EA-4A9C-8A83-8C0BC8144863}.Release|x86.ActiveCfg = Release|Any CPU - {C3A07F30-F2EA-4A9C-8A83-8C0BC8144863}.Release|x86.Build.0 = Release|Any CPU - {3A25A675-8867-420A-8921-4B6D617EBE2F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3A25A675-8867-420A-8921-4B6D617EBE2F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3A25A675-8867-420A-8921-4B6D617EBE2F}.Debug|x64.ActiveCfg = Debug|Any CPU - {3A25A675-8867-420A-8921-4B6D617EBE2F}.Debug|x64.Build.0 = Debug|Any CPU - {3A25A675-8867-420A-8921-4B6D617EBE2F}.Debug|x86.ActiveCfg = Debug|Any CPU - {3A25A675-8867-420A-8921-4B6D617EBE2F}.Debug|x86.Build.0 = Debug|Any CPU - {3A25A675-8867-420A-8921-4B6D617EBE2F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3A25A675-8867-420A-8921-4B6D617EBE2F}.Release|Any CPU.Build.0 = Release|Any CPU - {3A25A675-8867-420A-8921-4B6D617EBE2F}.Release|x64.ActiveCfg = Release|Any CPU - {3A25A675-8867-420A-8921-4B6D617EBE2F}.Release|x64.Build.0 = Release|Any CPU - {3A25A675-8867-420A-8921-4B6D617EBE2F}.Release|x86.ActiveCfg = Release|Any CPU - {3A25A675-8867-420A-8921-4B6D617EBE2F}.Release|x86.Build.0 = Release|Any CPU - {B25439E1-C944-4FE1-8678-AC9E866AC4EA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B25439E1-C944-4FE1-8678-AC9E866AC4EA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B25439E1-C944-4FE1-8678-AC9E866AC4EA}.Debug|x64.ActiveCfg = Debug|Any CPU - {B25439E1-C944-4FE1-8678-AC9E866AC4EA}.Debug|x64.Build.0 = Debug|Any CPU - {B25439E1-C944-4FE1-8678-AC9E866AC4EA}.Debug|x86.ActiveCfg = Debug|Any CPU - {B25439E1-C944-4FE1-8678-AC9E866AC4EA}.Debug|x86.Build.0 = Debug|Any CPU - {B25439E1-C944-4FE1-8678-AC9E866AC4EA}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B25439E1-C944-4FE1-8678-AC9E866AC4EA}.Release|Any CPU.Build.0 = Release|Any CPU - {B25439E1-C944-4FE1-8678-AC9E866AC4EA}.Release|x64.ActiveCfg = Release|Any CPU - {B25439E1-C944-4FE1-8678-AC9E866AC4EA}.Release|x64.Build.0 = Release|Any CPU - {B25439E1-C944-4FE1-8678-AC9E866AC4EA}.Release|x86.ActiveCfg = Release|Any CPU - {B25439E1-C944-4FE1-8678-AC9E866AC4EA}.Release|x86.Build.0 = Release|Any CPU - {214B9F12-BF3F-430F-85BC-98C6CFFFE5F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {214B9F12-BF3F-430F-85BC-98C6CFFFE5F8}.Debug|Any CPU.Build.0 = Debug|Any CPU - {214B9F12-BF3F-430F-85BC-98C6CFFFE5F8}.Debug|x64.ActiveCfg = Debug|Any CPU - {214B9F12-BF3F-430F-85BC-98C6CFFFE5F8}.Debug|x64.Build.0 = Debug|Any CPU - {214B9F12-BF3F-430F-85BC-98C6CFFFE5F8}.Debug|x86.ActiveCfg = Debug|Any CPU - {214B9F12-BF3F-430F-85BC-98C6CFFFE5F8}.Debug|x86.Build.0 = Debug|Any CPU - {214B9F12-BF3F-430F-85BC-98C6CFFFE5F8}.Release|Any CPU.ActiveCfg = Release|Any CPU - {214B9F12-BF3F-430F-85BC-98C6CFFFE5F8}.Release|Any CPU.Build.0 = Release|Any CPU - {214B9F12-BF3F-430F-85BC-98C6CFFFE5F8}.Release|x64.ActiveCfg = Release|Any CPU - {214B9F12-BF3F-430F-85BC-98C6CFFFE5F8}.Release|x64.Build.0 = Release|Any CPU - {214B9F12-BF3F-430F-85BC-98C6CFFFE5F8}.Release|x86.ActiveCfg = Release|Any CPU - {214B9F12-BF3F-430F-85BC-98C6CFFFE5F8}.Release|x86.Build.0 = Release|Any CPU - {574F245D-ED2E-4B5F-9929-8E8377412E6D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {574F245D-ED2E-4B5F-9929-8E8377412E6D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {574F245D-ED2E-4B5F-9929-8E8377412E6D}.Debug|x64.ActiveCfg = Debug|Any CPU - {574F245D-ED2E-4B5F-9929-8E8377412E6D}.Debug|x64.Build.0 = Debug|Any CPU - {574F245D-ED2E-4B5F-9929-8E8377412E6D}.Debug|x86.ActiveCfg = Debug|Any CPU - {574F245D-ED2E-4B5F-9929-8E8377412E6D}.Debug|x86.Build.0 = Debug|Any CPU - {574F245D-ED2E-4B5F-9929-8E8377412E6D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {574F245D-ED2E-4B5F-9929-8E8377412E6D}.Release|Any CPU.Build.0 = Release|Any CPU - {574F245D-ED2E-4B5F-9929-8E8377412E6D}.Release|x64.ActiveCfg = Release|Any CPU - {574F245D-ED2E-4B5F-9929-8E8377412E6D}.Release|x64.Build.0 = Release|Any CPU - {574F245D-ED2E-4B5F-9929-8E8377412E6D}.Release|x86.ActiveCfg = Release|Any CPU - {574F245D-ED2E-4B5F-9929-8E8377412E6D}.Release|x86.Build.0 = Release|Any CPU - {7BE4D31D-D31F-422E-8C54-39B91A9A4DE4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7BE4D31D-D31F-422E-8C54-39B91A9A4DE4}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7BE4D31D-D31F-422E-8C54-39B91A9A4DE4}.Debug|x64.ActiveCfg = Debug|Any CPU - {7BE4D31D-D31F-422E-8C54-39B91A9A4DE4}.Debug|x64.Build.0 = Debug|Any CPU - {7BE4D31D-D31F-422E-8C54-39B91A9A4DE4}.Debug|x86.ActiveCfg = Debug|Any CPU - {7BE4D31D-D31F-422E-8C54-39B91A9A4DE4}.Debug|x86.Build.0 = Debug|Any CPU - {7BE4D31D-D31F-422E-8C54-39B91A9A4DE4}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7BE4D31D-D31F-422E-8C54-39B91A9A4DE4}.Release|Any CPU.Build.0 = Release|Any CPU - {7BE4D31D-D31F-422E-8C54-39B91A9A4DE4}.Release|x64.ActiveCfg = Release|Any CPU - {7BE4D31D-D31F-422E-8C54-39B91A9A4DE4}.Release|x64.Build.0 = Release|Any CPU - {7BE4D31D-D31F-422E-8C54-39B91A9A4DE4}.Release|x86.ActiveCfg = Release|Any CPU - {7BE4D31D-D31F-422E-8C54-39B91A9A4DE4}.Release|x86.Build.0 = Release|Any CPU - {8EF63B6F-A1D9-469B-9A50-DE1613ED47A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8EF63B6F-A1D9-469B-9A50-DE1613ED47A5}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8EF63B6F-A1D9-469B-9A50-DE1613ED47A5}.Debug|x64.ActiveCfg = Debug|Any CPU - {8EF63B6F-A1D9-469B-9A50-DE1613ED47A5}.Debug|x64.Build.0 = Debug|Any CPU - {8EF63B6F-A1D9-469B-9A50-DE1613ED47A5}.Debug|x86.ActiveCfg = Debug|Any CPU - {8EF63B6F-A1D9-469B-9A50-DE1613ED47A5}.Debug|x86.Build.0 = Debug|Any CPU - {8EF63B6F-A1D9-469B-9A50-DE1613ED47A5}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8EF63B6F-A1D9-469B-9A50-DE1613ED47A5}.Release|Any CPU.Build.0 = Release|Any CPU - {8EF63B6F-A1D9-469B-9A50-DE1613ED47A5}.Release|x64.ActiveCfg = Release|Any CPU - {8EF63B6F-A1D9-469B-9A50-DE1613ED47A5}.Release|x64.Build.0 = Release|Any CPU - {8EF63B6F-A1D9-469B-9A50-DE1613ED47A5}.Release|x86.ActiveCfg = Release|Any CPU - {8EF63B6F-A1D9-469B-9A50-DE1613ED47A5}.Release|x86.Build.0 = Release|Any CPU - {A9291B4E-7049-4574-AC45-8D642AD3D9B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A9291B4E-7049-4574-AC45-8D642AD3D9B0}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A9291B4E-7049-4574-AC45-8D642AD3D9B0}.Debug|x64.ActiveCfg = Debug|Any CPU - {A9291B4E-7049-4574-AC45-8D642AD3D9B0}.Debug|x64.Build.0 = Debug|Any CPU - {A9291B4E-7049-4574-AC45-8D642AD3D9B0}.Debug|x86.ActiveCfg = Debug|Any CPU - {A9291B4E-7049-4574-AC45-8D642AD3D9B0}.Debug|x86.Build.0 = Debug|Any CPU - {A9291B4E-7049-4574-AC45-8D642AD3D9B0}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A9291B4E-7049-4574-AC45-8D642AD3D9B0}.Release|Any CPU.Build.0 = Release|Any CPU - {A9291B4E-7049-4574-AC45-8D642AD3D9B0}.Release|x64.ActiveCfg = Release|Any CPU - {A9291B4E-7049-4574-AC45-8D642AD3D9B0}.Release|x64.Build.0 = Release|Any CPU - {A9291B4E-7049-4574-AC45-8D642AD3D9B0}.Release|x86.ActiveCfg = Release|Any CPU - {A9291B4E-7049-4574-AC45-8D642AD3D9B0}.Release|x86.Build.0 = Release|Any CPU - {6B847B89-DEFB-478C-B0D8-0F309602A0C5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6B847B89-DEFB-478C-B0D8-0F309602A0C5}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6B847B89-DEFB-478C-B0D8-0F309602A0C5}.Debug|x64.ActiveCfg = Debug|Any CPU - {6B847B89-DEFB-478C-B0D8-0F309602A0C5}.Debug|x64.Build.0 = Debug|Any CPU - {6B847B89-DEFB-478C-B0D8-0F309602A0C5}.Debug|x86.ActiveCfg = Debug|Any CPU - {6B847B89-DEFB-478C-B0D8-0F309602A0C5}.Debug|x86.Build.0 = Debug|Any CPU - {6B847B89-DEFB-478C-B0D8-0F309602A0C5}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6B847B89-DEFB-478C-B0D8-0F309602A0C5}.Release|Any CPU.Build.0 = Release|Any CPU - {6B847B89-DEFB-478C-B0D8-0F309602A0C5}.Release|x64.ActiveCfg = Release|Any CPU - {6B847B89-DEFB-478C-B0D8-0F309602A0C5}.Release|x64.Build.0 = Release|Any CPU - {6B847B89-DEFB-478C-B0D8-0F309602A0C5}.Release|x86.ActiveCfg = Release|Any CPU - {6B847B89-DEFB-478C-B0D8-0F309602A0C5}.Release|x86.Build.0 = Release|Any CPU - {3D316CA9-55C6-4D72-A408-382935555361}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3D316CA9-55C6-4D72-A408-382935555361}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3D316CA9-55C6-4D72-A408-382935555361}.Debug|x64.ActiveCfg = Debug|Any CPU - {3D316CA9-55C6-4D72-A408-382935555361}.Debug|x64.Build.0 = Debug|Any CPU - {3D316CA9-55C6-4D72-A408-382935555361}.Debug|x86.ActiveCfg = Debug|Any CPU - {3D316CA9-55C6-4D72-A408-382935555361}.Debug|x86.Build.0 = Debug|Any CPU - {3D316CA9-55C6-4D72-A408-382935555361}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3D316CA9-55C6-4D72-A408-382935555361}.Release|Any CPU.Build.0 = Release|Any CPU - {3D316CA9-55C6-4D72-A408-382935555361}.Release|x64.ActiveCfg = Release|Any CPU - {3D316CA9-55C6-4D72-A408-382935555361}.Release|x64.Build.0 = Release|Any CPU - {3D316CA9-55C6-4D72-A408-382935555361}.Release|x86.ActiveCfg = Release|Any CPU - {3D316CA9-55C6-4D72-A408-382935555361}.Release|x86.Build.0 = Release|Any CPU - {E0EDCB3C-C93B-4368-9289-035D7D35382B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E0EDCB3C-C93B-4368-9289-035D7D35382B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E0EDCB3C-C93B-4368-9289-035D7D35382B}.Debug|x64.ActiveCfg = Debug|Any CPU - {E0EDCB3C-C93B-4368-9289-035D7D35382B}.Debug|x64.Build.0 = Debug|Any CPU - {E0EDCB3C-C93B-4368-9289-035D7D35382B}.Debug|x86.ActiveCfg = Debug|Any CPU - {E0EDCB3C-C93B-4368-9289-035D7D35382B}.Debug|x86.Build.0 = Debug|Any CPU - {E0EDCB3C-C93B-4368-9289-035D7D35382B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E0EDCB3C-C93B-4368-9289-035D7D35382B}.Release|Any CPU.Build.0 = Release|Any CPU - {E0EDCB3C-C93B-4368-9289-035D7D35382B}.Release|x64.ActiveCfg = Release|Any CPU - {E0EDCB3C-C93B-4368-9289-035D7D35382B}.Release|x64.Build.0 = Release|Any CPU - {E0EDCB3C-C93B-4368-9289-035D7D35382B}.Release|x86.ActiveCfg = Release|Any CPU - {E0EDCB3C-C93B-4368-9289-035D7D35382B}.Release|x86.Build.0 = Release|Any CPU - {3C001B2F-2A04-478C-8A7A-1D121E8A4BB1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3C001B2F-2A04-478C-8A7A-1D121E8A4BB1}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3C001B2F-2A04-478C-8A7A-1D121E8A4BB1}.Debug|x64.ActiveCfg = Debug|Any CPU - {3C001B2F-2A04-478C-8A7A-1D121E8A4BB1}.Debug|x64.Build.0 = Debug|Any CPU - {3C001B2F-2A04-478C-8A7A-1D121E8A4BB1}.Debug|x86.ActiveCfg = Debug|Any CPU - {3C001B2F-2A04-478C-8A7A-1D121E8A4BB1}.Debug|x86.Build.0 = Debug|Any CPU - {3C001B2F-2A04-478C-8A7A-1D121E8A4BB1}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3C001B2F-2A04-478C-8A7A-1D121E8A4BB1}.Release|Any CPU.Build.0 = Release|Any CPU - {3C001B2F-2A04-478C-8A7A-1D121E8A4BB1}.Release|x64.ActiveCfg = Release|Any CPU - {3C001B2F-2A04-478C-8A7A-1D121E8A4BB1}.Release|x64.Build.0 = Release|Any CPU - {3C001B2F-2A04-478C-8A7A-1D121E8A4BB1}.Release|x86.ActiveCfg = Release|Any CPU - {3C001B2F-2A04-478C-8A7A-1D121E8A4BB1}.Release|x86.Build.0 = Release|Any CPU - {FF3A5823-43F0-4C98-87C4-3C5973F3C7D7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {FF3A5823-43F0-4C98-87C4-3C5973F3C7D7}.Debug|Any CPU.Build.0 = Debug|Any CPU - {FF3A5823-43F0-4C98-87C4-3C5973F3C7D7}.Debug|x64.ActiveCfg = Debug|Any CPU - {FF3A5823-43F0-4C98-87C4-3C5973F3C7D7}.Debug|x64.Build.0 = Debug|Any CPU - {FF3A5823-43F0-4C98-87C4-3C5973F3C7D7}.Debug|x86.ActiveCfg = Debug|Any CPU - {FF3A5823-43F0-4C98-87C4-3C5973F3C7D7}.Debug|x86.Build.0 = Debug|Any CPU - {FF3A5823-43F0-4C98-87C4-3C5973F3C7D7}.Release|Any CPU.ActiveCfg = Release|Any CPU - {FF3A5823-43F0-4C98-87C4-3C5973F3C7D7}.Release|Any CPU.Build.0 = Release|Any CPU - {FF3A5823-43F0-4C98-87C4-3C5973F3C7D7}.Release|x64.ActiveCfg = Release|Any CPU - {FF3A5823-43F0-4C98-87C4-3C5973F3C7D7}.Release|x64.Build.0 = Release|Any CPU - {FF3A5823-43F0-4C98-87C4-3C5973F3C7D7}.Release|x86.ActiveCfg = Release|Any CPU - {FF3A5823-43F0-4C98-87C4-3C5973F3C7D7}.Release|x86.Build.0 = Release|Any CPU - {AB47EF50-D7F4-47AB-A49D-FFB8874EC9F7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {AB47EF50-D7F4-47AB-A49D-FFB8874EC9F7}.Debug|Any CPU.Build.0 = Debug|Any CPU - {AB47EF50-D7F4-47AB-A49D-FFB8874EC9F7}.Debug|x64.ActiveCfg = Debug|Any CPU - {AB47EF50-D7F4-47AB-A49D-FFB8874EC9F7}.Debug|x64.Build.0 = Debug|Any CPU - {AB47EF50-D7F4-47AB-A49D-FFB8874EC9F7}.Debug|x86.ActiveCfg = Debug|Any CPU - {AB47EF50-D7F4-47AB-A49D-FFB8874EC9F7}.Debug|x86.Build.0 = Debug|Any CPU - {AB47EF50-D7F4-47AB-A49D-FFB8874EC9F7}.Release|Any CPU.ActiveCfg = Release|Any CPU - {AB47EF50-D7F4-47AB-A49D-FFB8874EC9F7}.Release|Any CPU.Build.0 = Release|Any CPU - {AB47EF50-D7F4-47AB-A49D-FFB8874EC9F7}.Release|x64.ActiveCfg = Release|Any CPU - {AB47EF50-D7F4-47AB-A49D-FFB8874EC9F7}.Release|x64.Build.0 = Release|Any CPU - {AB47EF50-D7F4-47AB-A49D-FFB8874EC9F7}.Release|x86.ActiveCfg = Release|Any CPU - {AB47EF50-D7F4-47AB-A49D-FFB8874EC9F7}.Release|x86.Build.0 = Release|Any CPU - {8C18A50B-EAEE-4CE0-8FFC-0957FD6B5DFD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8C18A50B-EAEE-4CE0-8FFC-0957FD6B5DFD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8C18A50B-EAEE-4CE0-8FFC-0957FD6B5DFD}.Debug|x64.ActiveCfg = Debug|Any CPU - {8C18A50B-EAEE-4CE0-8FFC-0957FD6B5DFD}.Debug|x64.Build.0 = Debug|Any CPU - {8C18A50B-EAEE-4CE0-8FFC-0957FD6B5DFD}.Debug|x86.ActiveCfg = Debug|Any CPU - {8C18A50B-EAEE-4CE0-8FFC-0957FD6B5DFD}.Debug|x86.Build.0 = Debug|Any CPU - {8C18A50B-EAEE-4CE0-8FFC-0957FD6B5DFD}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8C18A50B-EAEE-4CE0-8FFC-0957FD6B5DFD}.Release|Any CPU.Build.0 = Release|Any CPU - {8C18A50B-EAEE-4CE0-8FFC-0957FD6B5DFD}.Release|x64.ActiveCfg = Release|Any CPU - {8C18A50B-EAEE-4CE0-8FFC-0957FD6B5DFD}.Release|x64.Build.0 = Release|Any CPU - {8C18A50B-EAEE-4CE0-8FFC-0957FD6B5DFD}.Release|x86.ActiveCfg = Release|Any CPU - {8C18A50B-EAEE-4CE0-8FFC-0957FD6B5DFD}.Release|x86.Build.0 = Release|Any CPU - {6F46EE1F-5A3A-4D16-94C4-6CF7147BC75B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6F46EE1F-5A3A-4D16-94C4-6CF7147BC75B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6F46EE1F-5A3A-4D16-94C4-6CF7147BC75B}.Debug|x64.ActiveCfg = Debug|Any CPU - {6F46EE1F-5A3A-4D16-94C4-6CF7147BC75B}.Debug|x64.Build.0 = Debug|Any CPU - {6F46EE1F-5A3A-4D16-94C4-6CF7147BC75B}.Debug|x86.ActiveCfg = Debug|Any CPU - {6F46EE1F-5A3A-4D16-94C4-6CF7147BC75B}.Debug|x86.Build.0 = Debug|Any CPU - {6F46EE1F-5A3A-4D16-94C4-6CF7147BC75B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6F46EE1F-5A3A-4D16-94C4-6CF7147BC75B}.Release|Any CPU.Build.0 = Release|Any CPU - {6F46EE1F-5A3A-4D16-94C4-6CF7147BC75B}.Release|x64.ActiveCfg = Release|Any CPU - {6F46EE1F-5A3A-4D16-94C4-6CF7147BC75B}.Release|x64.Build.0 = Release|Any CPU - {6F46EE1F-5A3A-4D16-94C4-6CF7147BC75B}.Release|x86.ActiveCfg = Release|Any CPU - {6F46EE1F-5A3A-4D16-94C4-6CF7147BC75B}.Release|x86.Build.0 = Release|Any CPU - {EF6E0BF5-F018-4C76-A7E8-EF52D2C7D9C1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {EF6E0BF5-F018-4C76-A7E8-EF52D2C7D9C1}.Debug|Any CPU.Build.0 = Debug|Any CPU - {EF6E0BF5-F018-4C76-A7E8-EF52D2C7D9C1}.Debug|x64.ActiveCfg = Debug|Any CPU - {EF6E0BF5-F018-4C76-A7E8-EF52D2C7D9C1}.Debug|x64.Build.0 = Debug|Any CPU - {EF6E0BF5-F018-4C76-A7E8-EF52D2C7D9C1}.Debug|x86.ActiveCfg = Debug|Any CPU - {EF6E0BF5-F018-4C76-A7E8-EF52D2C7D9C1}.Debug|x86.Build.0 = Debug|Any CPU - {EF6E0BF5-F018-4C76-A7E8-EF52D2C7D9C1}.Release|Any CPU.ActiveCfg = Release|Any CPU - {EF6E0BF5-F018-4C76-A7E8-EF52D2C7D9C1}.Release|Any CPU.Build.0 = Release|Any CPU - {EF6E0BF5-F018-4C76-A7E8-EF52D2C7D9C1}.Release|x64.ActiveCfg = Release|Any CPU - {EF6E0BF5-F018-4C76-A7E8-EF52D2C7D9C1}.Release|x64.Build.0 = Release|Any CPU - {EF6E0BF5-F018-4C76-A7E8-EF52D2C7D9C1}.Release|x86.ActiveCfg = Release|Any CPU - {EF6E0BF5-F018-4C76-A7E8-EF52D2C7D9C1}.Release|x86.Build.0 = Release|Any CPU - {697B279A-8BC0-49C2-A57F-667E9AD81E9A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {697B279A-8BC0-49C2-A57F-667E9AD81E9A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {697B279A-8BC0-49C2-A57F-667E9AD81E9A}.Debug|x64.ActiveCfg = Debug|Any CPU - {697B279A-8BC0-49C2-A57F-667E9AD81E9A}.Debug|x64.Build.0 = Debug|Any CPU - {697B279A-8BC0-49C2-A57F-667E9AD81E9A}.Debug|x86.ActiveCfg = Debug|Any CPU - {697B279A-8BC0-49C2-A57F-667E9AD81E9A}.Debug|x86.Build.0 = Debug|Any CPU - {697B279A-8BC0-49C2-A57F-667E9AD81E9A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {697B279A-8BC0-49C2-A57F-667E9AD81E9A}.Release|Any CPU.Build.0 = Release|Any CPU - {697B279A-8BC0-49C2-A57F-667E9AD81E9A}.Release|x64.ActiveCfg = Release|Any CPU - {697B279A-8BC0-49C2-A57F-667E9AD81E9A}.Release|x64.Build.0 = Release|Any CPU - {697B279A-8BC0-49C2-A57F-667E9AD81E9A}.Release|x86.ActiveCfg = Release|Any CPU - {697B279A-8BC0-49C2-A57F-667E9AD81E9A}.Release|x86.Build.0 = Release|Any CPU - {F94690E9-258C-4C10-AC26-FA31F6EB9D35}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F94690E9-258C-4C10-AC26-FA31F6EB9D35}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F94690E9-258C-4C10-AC26-FA31F6EB9D35}.Debug|x64.ActiveCfg = Debug|Any CPU - {F94690E9-258C-4C10-AC26-FA31F6EB9D35}.Debug|x64.Build.0 = Debug|Any CPU - {F94690E9-258C-4C10-AC26-FA31F6EB9D35}.Debug|x86.ActiveCfg = Debug|Any CPU - {F94690E9-258C-4C10-AC26-FA31F6EB9D35}.Debug|x86.Build.0 = Debug|Any CPU - {F94690E9-258C-4C10-AC26-FA31F6EB9D35}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F94690E9-258C-4C10-AC26-FA31F6EB9D35}.Release|Any CPU.Build.0 = Release|Any CPU - {F94690E9-258C-4C10-AC26-FA31F6EB9D35}.Release|x64.ActiveCfg = Release|Any CPU - {F94690E9-258C-4C10-AC26-FA31F6EB9D35}.Release|x64.Build.0 = Release|Any CPU - {F94690E9-258C-4C10-AC26-FA31F6EB9D35}.Release|x86.ActiveCfg = Release|Any CPU - {F94690E9-258C-4C10-AC26-FA31F6EB9D35}.Release|x86.Build.0 = Release|Any CPU - {A2AB7E2D-0FE2-4740-95E7-CE600CBD4F44}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A2AB7E2D-0FE2-4740-95E7-CE600CBD4F44}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A2AB7E2D-0FE2-4740-95E7-CE600CBD4F44}.Debug|x64.ActiveCfg = Debug|Any CPU - {A2AB7E2D-0FE2-4740-95E7-CE600CBD4F44}.Debug|x64.Build.0 = Debug|Any CPU - {A2AB7E2D-0FE2-4740-95E7-CE600CBD4F44}.Debug|x86.ActiveCfg = Debug|Any CPU - {A2AB7E2D-0FE2-4740-95E7-CE600CBD4F44}.Debug|x86.Build.0 = Debug|Any CPU - {A2AB7E2D-0FE2-4740-95E7-CE600CBD4F44}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A2AB7E2D-0FE2-4740-95E7-CE600CBD4F44}.Release|Any CPU.Build.0 = Release|Any CPU - {A2AB7E2D-0FE2-4740-95E7-CE600CBD4F44}.Release|x64.ActiveCfg = Release|Any CPU - {A2AB7E2D-0FE2-4740-95E7-CE600CBD4F44}.Release|x64.Build.0 = Release|Any CPU - {A2AB7E2D-0FE2-4740-95E7-CE600CBD4F44}.Release|x86.ActiveCfg = Release|Any CPU - {A2AB7E2D-0FE2-4740-95E7-CE600CBD4F44}.Release|x86.Build.0 = Release|Any CPU - {71209D14-8469-40FB-B052-8308AF22A0EC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {71209D14-8469-40FB-B052-8308AF22A0EC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {71209D14-8469-40FB-B052-8308AF22A0EC}.Debug|x64.ActiveCfg = Debug|Any CPU - {71209D14-8469-40FB-B052-8308AF22A0EC}.Debug|x64.Build.0 = Debug|Any CPU - {71209D14-8469-40FB-B052-8308AF22A0EC}.Debug|x86.ActiveCfg = Debug|Any CPU - {71209D14-8469-40FB-B052-8308AF22A0EC}.Debug|x86.Build.0 = Debug|Any CPU - {71209D14-8469-40FB-B052-8308AF22A0EC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {71209D14-8469-40FB-B052-8308AF22A0EC}.Release|Any CPU.Build.0 = Release|Any CPU - {71209D14-8469-40FB-B052-8308AF22A0EC}.Release|x64.ActiveCfg = Release|Any CPU - {71209D14-8469-40FB-B052-8308AF22A0EC}.Release|x64.Build.0 = Release|Any CPU - {71209D14-8469-40FB-B052-8308AF22A0EC}.Release|x86.ActiveCfg = Release|Any CPU - {71209D14-8469-40FB-B052-8308AF22A0EC}.Release|x86.Build.0 = Release|Any CPU - {86CBF0C9-76C8-4084-9758-E36731AEC1D7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {86CBF0C9-76C8-4084-9758-E36731AEC1D7}.Debug|Any CPU.Build.0 = Debug|Any CPU - {86CBF0C9-76C8-4084-9758-E36731AEC1D7}.Debug|x64.ActiveCfg = Debug|Any CPU - {86CBF0C9-76C8-4084-9758-E36731AEC1D7}.Debug|x64.Build.0 = Debug|Any CPU - {86CBF0C9-76C8-4084-9758-E36731AEC1D7}.Debug|x86.ActiveCfg = Debug|Any CPU - {86CBF0C9-76C8-4084-9758-E36731AEC1D7}.Debug|x86.Build.0 = Debug|Any CPU - {86CBF0C9-76C8-4084-9758-E36731AEC1D7}.Release|Any CPU.ActiveCfg = Release|Any CPU - {86CBF0C9-76C8-4084-9758-E36731AEC1D7}.Release|Any CPU.Build.0 = Release|Any CPU - {86CBF0C9-76C8-4084-9758-E36731AEC1D7}.Release|x64.ActiveCfg = Release|Any CPU - {86CBF0C9-76C8-4084-9758-E36731AEC1D7}.Release|x64.Build.0 = Release|Any CPU - {86CBF0C9-76C8-4084-9758-E36731AEC1D7}.Release|x86.ActiveCfg = Release|Any CPU - {86CBF0C9-76C8-4084-9758-E36731AEC1D7}.Release|x86.Build.0 = Release|Any CPU - {EA169B0E-3F8C-4436-82F4-56768263D256}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {EA169B0E-3F8C-4436-82F4-56768263D256}.Debug|Any CPU.Build.0 = Debug|Any CPU - {EA169B0E-3F8C-4436-82F4-56768263D256}.Debug|x64.ActiveCfg = Debug|Any CPU - {EA169B0E-3F8C-4436-82F4-56768263D256}.Debug|x64.Build.0 = Debug|Any CPU - {EA169B0E-3F8C-4436-82F4-56768263D256}.Debug|x86.ActiveCfg = Debug|Any CPU - {EA169B0E-3F8C-4436-82F4-56768263D256}.Debug|x86.Build.0 = Debug|Any CPU - {EA169B0E-3F8C-4436-82F4-56768263D256}.Release|Any CPU.ActiveCfg = Release|Any CPU - {EA169B0E-3F8C-4436-82F4-56768263D256}.Release|Any CPU.Build.0 = Release|Any CPU - {EA169B0E-3F8C-4436-82F4-56768263D256}.Release|x64.ActiveCfg = Release|Any CPU - {EA169B0E-3F8C-4436-82F4-56768263D256}.Release|x64.Build.0 = Release|Any CPU - {EA169B0E-3F8C-4436-82F4-56768263D256}.Release|x86.ActiveCfg = Release|Any CPU - {EA169B0E-3F8C-4436-82F4-56768263D256}.Release|x86.Build.0 = Release|Any CPU - {1CDF7EC6-A25A-44BC-8CD3-C9F6AD13CF0B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1CDF7EC6-A25A-44BC-8CD3-C9F6AD13CF0B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1CDF7EC6-A25A-44BC-8CD3-C9F6AD13CF0B}.Debug|x64.ActiveCfg = Debug|Any CPU - {1CDF7EC6-A25A-44BC-8CD3-C9F6AD13CF0B}.Debug|x64.Build.0 = Debug|Any CPU - {1CDF7EC6-A25A-44BC-8CD3-C9F6AD13CF0B}.Debug|x86.ActiveCfg = Debug|Any CPU - {1CDF7EC6-A25A-44BC-8CD3-C9F6AD13CF0B}.Debug|x86.Build.0 = Debug|Any CPU - {1CDF7EC6-A25A-44BC-8CD3-C9F6AD13CF0B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1CDF7EC6-A25A-44BC-8CD3-C9F6AD13CF0B}.Release|Any CPU.Build.0 = Release|Any CPU - {1CDF7EC6-A25A-44BC-8CD3-C9F6AD13CF0B}.Release|x64.ActiveCfg = Release|Any CPU - {1CDF7EC6-A25A-44BC-8CD3-C9F6AD13CF0B}.Release|x64.Build.0 = Release|Any CPU - {1CDF7EC6-A25A-44BC-8CD3-C9F6AD13CF0B}.Release|x86.ActiveCfg = Release|Any CPU - {1CDF7EC6-A25A-44BC-8CD3-C9F6AD13CF0B}.Release|x86.Build.0 = Release|Any CPU - {5AEEAA34-01A0-418D-A8D0-E89A5B9A0EF1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5AEEAA34-01A0-418D-A8D0-E89A5B9A0EF1}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5AEEAA34-01A0-418D-A8D0-E89A5B9A0EF1}.Debug|x64.ActiveCfg = Debug|Any CPU - {5AEEAA34-01A0-418D-A8D0-E89A5B9A0EF1}.Debug|x64.Build.0 = Debug|Any CPU - {5AEEAA34-01A0-418D-A8D0-E89A5B9A0EF1}.Debug|x86.ActiveCfg = Debug|Any CPU - {5AEEAA34-01A0-418D-A8D0-E89A5B9A0EF1}.Debug|x86.Build.0 = Debug|Any CPU - {5AEEAA34-01A0-418D-A8D0-E89A5B9A0EF1}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5AEEAA34-01A0-418D-A8D0-E89A5B9A0EF1}.Release|Any CPU.Build.0 = Release|Any CPU - {5AEEAA34-01A0-418D-A8D0-E89A5B9A0EF1}.Release|x64.ActiveCfg = Release|Any CPU - {5AEEAA34-01A0-418D-A8D0-E89A5B9A0EF1}.Release|x64.Build.0 = Release|Any CPU - {5AEEAA34-01A0-418D-A8D0-E89A5B9A0EF1}.Release|x86.ActiveCfg = Release|Any CPU - {5AEEAA34-01A0-418D-A8D0-E89A5B9A0EF1}.Release|x86.Build.0 = Release|Any CPU - {BBDB70EB-2C08-43E7-8D82-BEE18C8881C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {BBDB70EB-2C08-43E7-8D82-BEE18C8881C8}.Debug|Any CPU.Build.0 = Debug|Any CPU - {BBDB70EB-2C08-43E7-8D82-BEE18C8881C8}.Debug|x64.ActiveCfg = Debug|Any CPU - {BBDB70EB-2C08-43E7-8D82-BEE18C8881C8}.Debug|x64.Build.0 = Debug|Any CPU - {BBDB70EB-2C08-43E7-8D82-BEE18C8881C8}.Debug|x86.ActiveCfg = Debug|Any CPU - {BBDB70EB-2C08-43E7-8D82-BEE18C8881C8}.Debug|x86.Build.0 = Debug|Any CPU - {BBDB70EB-2C08-43E7-8D82-BEE18C8881C8}.Release|Any CPU.ActiveCfg = Release|Any CPU - {BBDB70EB-2C08-43E7-8D82-BEE18C8881C8}.Release|Any CPU.Build.0 = Release|Any CPU - {BBDB70EB-2C08-43E7-8D82-BEE18C8881C8}.Release|x64.ActiveCfg = Release|Any CPU - {BBDB70EB-2C08-43E7-8D82-BEE18C8881C8}.Release|x64.Build.0 = Release|Any CPU - {BBDB70EB-2C08-43E7-8D82-BEE18C8881C8}.Release|x86.ActiveCfg = Release|Any CPU - {BBDB70EB-2C08-43E7-8D82-BEE18C8881C8}.Release|x86.Build.0 = Release|Any CPU - {AB827016-9D0A-4443-BFF0-80CB9E947D39}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {AB827016-9D0A-4443-BFF0-80CB9E947D39}.Debug|Any CPU.Build.0 = Debug|Any CPU - {AB827016-9D0A-4443-BFF0-80CB9E947D39}.Debug|x64.ActiveCfg = Debug|Any CPU - {AB827016-9D0A-4443-BFF0-80CB9E947D39}.Debug|x64.Build.0 = Debug|Any CPU - {AB827016-9D0A-4443-BFF0-80CB9E947D39}.Debug|x86.ActiveCfg = Debug|Any CPU - {AB827016-9D0A-4443-BFF0-80CB9E947D39}.Debug|x86.Build.0 = Debug|Any CPU - {AB827016-9D0A-4443-BFF0-80CB9E947D39}.Release|Any CPU.ActiveCfg = Release|Any CPU - {AB827016-9D0A-4443-BFF0-80CB9E947D39}.Release|Any CPU.Build.0 = Release|Any CPU - {AB827016-9D0A-4443-BFF0-80CB9E947D39}.Release|x64.ActiveCfg = Release|Any CPU - {AB827016-9D0A-4443-BFF0-80CB9E947D39}.Release|x64.Build.0 = Release|Any CPU - {AB827016-9D0A-4443-BFF0-80CB9E947D39}.Release|x86.ActiveCfg = Release|Any CPU - {AB827016-9D0A-4443-BFF0-80CB9E947D39}.Release|x86.Build.0 = Release|Any CPU - {707BB7F9-3E71-4364-8AD0-949735B5D33C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {707BB7F9-3E71-4364-8AD0-949735B5D33C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {707BB7F9-3E71-4364-8AD0-949735B5D33C}.Debug|x64.ActiveCfg = Debug|Any CPU - {707BB7F9-3E71-4364-8AD0-949735B5D33C}.Debug|x64.Build.0 = Debug|Any CPU - {707BB7F9-3E71-4364-8AD0-949735B5D33C}.Debug|x86.ActiveCfg = Debug|Any CPU - {707BB7F9-3E71-4364-8AD0-949735B5D33C}.Debug|x86.Build.0 = Debug|Any CPU - {707BB7F9-3E71-4364-8AD0-949735B5D33C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {707BB7F9-3E71-4364-8AD0-949735B5D33C}.Release|Any CPU.Build.0 = Release|Any CPU - {707BB7F9-3E71-4364-8AD0-949735B5D33C}.Release|x64.ActiveCfg = Release|Any CPU - {707BB7F9-3E71-4364-8AD0-949735B5D33C}.Release|x64.Build.0 = Release|Any CPU - {707BB7F9-3E71-4364-8AD0-949735B5D33C}.Release|x86.ActiveCfg = Release|Any CPU - {707BB7F9-3E71-4364-8AD0-949735B5D33C}.Release|x86.Build.0 = Release|Any CPU - {E09006B7-2022-43CD-A0D9-127282F95A57}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E09006B7-2022-43CD-A0D9-127282F95A57}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E09006B7-2022-43CD-A0D9-127282F95A57}.Debug|x64.ActiveCfg = Debug|Any CPU - {E09006B7-2022-43CD-A0D9-127282F95A57}.Debug|x64.Build.0 = Debug|Any CPU - {E09006B7-2022-43CD-A0D9-127282F95A57}.Debug|x86.ActiveCfg = Debug|Any CPU - {E09006B7-2022-43CD-A0D9-127282F95A57}.Debug|x86.Build.0 = Debug|Any CPU - {E09006B7-2022-43CD-A0D9-127282F95A57}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E09006B7-2022-43CD-A0D9-127282F95A57}.Release|Any CPU.Build.0 = Release|Any CPU - {E09006B7-2022-43CD-A0D9-127282F95A57}.Release|x64.ActiveCfg = Release|Any CPU - {E09006B7-2022-43CD-A0D9-127282F95A57}.Release|x64.Build.0 = Release|Any CPU - {E09006B7-2022-43CD-A0D9-127282F95A57}.Release|x86.ActiveCfg = Release|Any CPU - {E09006B7-2022-43CD-A0D9-127282F95A57}.Release|x86.Build.0 = Release|Any CPU - {61E8C8E2-1CF4-42DA-8822-AFEC7FA47F16}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {61E8C8E2-1CF4-42DA-8822-AFEC7FA47F16}.Debug|Any CPU.Build.0 = Debug|Any CPU - {61E8C8E2-1CF4-42DA-8822-AFEC7FA47F16}.Debug|x64.ActiveCfg = Debug|Any CPU - {61E8C8E2-1CF4-42DA-8822-AFEC7FA47F16}.Debug|x64.Build.0 = Debug|Any CPU - {61E8C8E2-1CF4-42DA-8822-AFEC7FA47F16}.Debug|x86.ActiveCfg = Debug|Any CPU - {61E8C8E2-1CF4-42DA-8822-AFEC7FA47F16}.Debug|x86.Build.0 = Debug|Any CPU - {61E8C8E2-1CF4-42DA-8822-AFEC7FA47F16}.Release|Any CPU.ActiveCfg = Release|Any CPU - {61E8C8E2-1CF4-42DA-8822-AFEC7FA47F16}.Release|Any CPU.Build.0 = Release|Any CPU - {61E8C8E2-1CF4-42DA-8822-AFEC7FA47F16}.Release|x64.ActiveCfg = Release|Any CPU - {61E8C8E2-1CF4-42DA-8822-AFEC7FA47F16}.Release|x64.Build.0 = Release|Any CPU - {61E8C8E2-1CF4-42DA-8822-AFEC7FA47F16}.Release|x86.ActiveCfg = Release|Any CPU - {61E8C8E2-1CF4-42DA-8822-AFEC7FA47F16}.Release|x86.Build.0 = Release|Any CPU - {1F501D4D-CEA4-445B-86C9-7215A6811368}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1F501D4D-CEA4-445B-86C9-7215A6811368}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1F501D4D-CEA4-445B-86C9-7215A6811368}.Debug|x64.ActiveCfg = Debug|Any CPU - {1F501D4D-CEA4-445B-86C9-7215A6811368}.Debug|x64.Build.0 = Debug|Any CPU - {1F501D4D-CEA4-445B-86C9-7215A6811368}.Debug|x86.ActiveCfg = Debug|Any CPU - {1F501D4D-CEA4-445B-86C9-7215A6811368}.Debug|x86.Build.0 = Debug|Any CPU - {1F501D4D-CEA4-445B-86C9-7215A6811368}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1F501D4D-CEA4-445B-86C9-7215A6811368}.Release|Any CPU.Build.0 = Release|Any CPU - {1F501D4D-CEA4-445B-86C9-7215A6811368}.Release|x64.ActiveCfg = Release|Any CPU - {1F501D4D-CEA4-445B-86C9-7215A6811368}.Release|x64.Build.0 = Release|Any CPU - {1F501D4D-CEA4-445B-86C9-7215A6811368}.Release|x86.ActiveCfg = Release|Any CPU - {1F501D4D-CEA4-445B-86C9-7215A6811368}.Release|x86.Build.0 = Release|Any CPU - {B5037DC9-2690-42FA-8725-514E4A9EFEAD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B5037DC9-2690-42FA-8725-514E4A9EFEAD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B5037DC9-2690-42FA-8725-514E4A9EFEAD}.Debug|x64.ActiveCfg = Debug|Any CPU - {B5037DC9-2690-42FA-8725-514E4A9EFEAD}.Debug|x64.Build.0 = Debug|Any CPU - {B5037DC9-2690-42FA-8725-514E4A9EFEAD}.Debug|x86.ActiveCfg = Debug|Any CPU - {B5037DC9-2690-42FA-8725-514E4A9EFEAD}.Debug|x86.Build.0 = Debug|Any CPU - {B5037DC9-2690-42FA-8725-514E4A9EFEAD}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B5037DC9-2690-42FA-8725-514E4A9EFEAD}.Release|Any CPU.Build.0 = Release|Any CPU - {B5037DC9-2690-42FA-8725-514E4A9EFEAD}.Release|x64.ActiveCfg = Release|Any CPU - {B5037DC9-2690-42FA-8725-514E4A9EFEAD}.Release|x64.Build.0 = Release|Any CPU - {B5037DC9-2690-42FA-8725-514E4A9EFEAD}.Release|x86.ActiveCfg = Release|Any CPU - {B5037DC9-2690-42FA-8725-514E4A9EFEAD}.Release|x86.Build.0 = Release|Any CPU - {AC7782F2-1F03-4615-A600-A7FE0FDEC5E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {AC7782F2-1F03-4615-A600-A7FE0FDEC5E5}.Debug|Any CPU.Build.0 = Debug|Any CPU - {AC7782F2-1F03-4615-A600-A7FE0FDEC5E5}.Debug|x64.ActiveCfg = Debug|Any CPU - {AC7782F2-1F03-4615-A600-A7FE0FDEC5E5}.Debug|x64.Build.0 = Debug|Any CPU - {AC7782F2-1F03-4615-A600-A7FE0FDEC5E5}.Debug|x86.ActiveCfg = Debug|Any CPU - {AC7782F2-1F03-4615-A600-A7FE0FDEC5E5}.Debug|x86.Build.0 = Debug|Any CPU - {AC7782F2-1F03-4615-A600-A7FE0FDEC5E5}.Release|Any CPU.ActiveCfg = Release|Any CPU - {AC7782F2-1F03-4615-A600-A7FE0FDEC5E5}.Release|Any CPU.Build.0 = Release|Any CPU - {AC7782F2-1F03-4615-A600-A7FE0FDEC5E5}.Release|x64.ActiveCfg = Release|Any CPU - {AC7782F2-1F03-4615-A600-A7FE0FDEC5E5}.Release|x64.Build.0 = Release|Any CPU - {AC7782F2-1F03-4615-A600-A7FE0FDEC5E5}.Release|x86.ActiveCfg = Release|Any CPU - {AC7782F2-1F03-4615-A600-A7FE0FDEC5E5}.Release|x86.Build.0 = Release|Any CPU - {D5C02B69-4E7B-4628-8BDA-B622A2FB2A97}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D5C02B69-4E7B-4628-8BDA-B622A2FB2A97}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D5C02B69-4E7B-4628-8BDA-B622A2FB2A97}.Debug|x64.ActiveCfg = Debug|Any CPU - {D5C02B69-4E7B-4628-8BDA-B622A2FB2A97}.Debug|x64.Build.0 = Debug|Any CPU - {D5C02B69-4E7B-4628-8BDA-B622A2FB2A97}.Debug|x86.ActiveCfg = Debug|Any CPU - {D5C02B69-4E7B-4628-8BDA-B622A2FB2A97}.Debug|x86.Build.0 = Debug|Any CPU - {D5C02B69-4E7B-4628-8BDA-B622A2FB2A97}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D5C02B69-4E7B-4628-8BDA-B622A2FB2A97}.Release|Any CPU.Build.0 = Release|Any CPU - {D5C02B69-4E7B-4628-8BDA-B622A2FB2A97}.Release|x64.ActiveCfg = Release|Any CPU - {D5C02B69-4E7B-4628-8BDA-B622A2FB2A97}.Release|x64.Build.0 = Release|Any CPU - {D5C02B69-4E7B-4628-8BDA-B622A2FB2A97}.Release|x86.ActiveCfg = Release|Any CPU - {D5C02B69-4E7B-4628-8BDA-B622A2FB2A97}.Release|x86.Build.0 = Release|Any CPU - {74F10D31-161F-49A4-ACD7-282211447CE4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {74F10D31-161F-49A4-ACD7-282211447CE4}.Debug|Any CPU.Build.0 = Debug|Any CPU - {74F10D31-161F-49A4-ACD7-282211447CE4}.Debug|x64.ActiveCfg = Debug|Any CPU - {74F10D31-161F-49A4-ACD7-282211447CE4}.Debug|x64.Build.0 = Debug|Any CPU - {74F10D31-161F-49A4-ACD7-282211447CE4}.Debug|x86.ActiveCfg = Debug|Any CPU - {74F10D31-161F-49A4-ACD7-282211447CE4}.Debug|x86.Build.0 = Debug|Any CPU - {74F10D31-161F-49A4-ACD7-282211447CE4}.Release|Any CPU.ActiveCfg = Release|Any CPU - {74F10D31-161F-49A4-ACD7-282211447CE4}.Release|Any CPU.Build.0 = Release|Any CPU - {74F10D31-161F-49A4-ACD7-282211447CE4}.Release|x64.ActiveCfg = Release|Any CPU - {74F10D31-161F-49A4-ACD7-282211447CE4}.Release|x64.Build.0 = Release|Any CPU - {74F10D31-161F-49A4-ACD7-282211447CE4}.Release|x86.ActiveCfg = Release|Any CPU - {74F10D31-161F-49A4-ACD7-282211447CE4}.Release|x86.Build.0 = Release|Any CPU - {DBA8E5FE-DE74-4E24-A9A2-0FBBCC1C2792}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DBA8E5FE-DE74-4E24-A9A2-0FBBCC1C2792}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DBA8E5FE-DE74-4E24-A9A2-0FBBCC1C2792}.Debug|x64.ActiveCfg = Debug|Any CPU - {DBA8E5FE-DE74-4E24-A9A2-0FBBCC1C2792}.Debug|x64.Build.0 = Debug|Any CPU - {DBA8E5FE-DE74-4E24-A9A2-0FBBCC1C2792}.Debug|x86.ActiveCfg = Debug|Any CPU - {DBA8E5FE-DE74-4E24-A9A2-0FBBCC1C2792}.Debug|x86.Build.0 = Debug|Any CPU - {DBA8E5FE-DE74-4E24-A9A2-0FBBCC1C2792}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DBA8E5FE-DE74-4E24-A9A2-0FBBCC1C2792}.Release|Any CPU.Build.0 = Release|Any CPU - {DBA8E5FE-DE74-4E24-A9A2-0FBBCC1C2792}.Release|x64.ActiveCfg = Release|Any CPU - {DBA8E5FE-DE74-4E24-A9A2-0FBBCC1C2792}.Release|x64.Build.0 = Release|Any CPU - {DBA8E5FE-DE74-4E24-A9A2-0FBBCC1C2792}.Release|x86.ActiveCfg = Release|Any CPU - {DBA8E5FE-DE74-4E24-A9A2-0FBBCC1C2792}.Release|x86.Build.0 = Release|Any CPU - {2BBA2091-C991-4696-B70F-5C2D114D5674}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2BBA2091-C991-4696-B70F-5C2D114D5674}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2BBA2091-C991-4696-B70F-5C2D114D5674}.Debug|x64.ActiveCfg = Debug|Any CPU - {2BBA2091-C991-4696-B70F-5C2D114D5674}.Debug|x64.Build.0 = Debug|Any CPU - {2BBA2091-C991-4696-B70F-5C2D114D5674}.Debug|x86.ActiveCfg = Debug|Any CPU - {2BBA2091-C991-4696-B70F-5C2D114D5674}.Debug|x86.Build.0 = Debug|Any CPU - {2BBA2091-C991-4696-B70F-5C2D114D5674}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2BBA2091-C991-4696-B70F-5C2D114D5674}.Release|Any CPU.Build.0 = Release|Any CPU - {2BBA2091-C991-4696-B70F-5C2D114D5674}.Release|x64.ActiveCfg = Release|Any CPU - {2BBA2091-C991-4696-B70F-5C2D114D5674}.Release|x64.Build.0 = Release|Any CPU - {2BBA2091-C991-4696-B70F-5C2D114D5674}.Release|x86.ActiveCfg = Release|Any CPU - {2BBA2091-C991-4696-B70F-5C2D114D5674}.Release|x86.Build.0 = Release|Any CPU - {D9E125B3-8FFD-47CE-9C0E-FF5CEAF633AE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D9E125B3-8FFD-47CE-9C0E-FF5CEAF633AE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D9E125B3-8FFD-47CE-9C0E-FF5CEAF633AE}.Debug|x64.ActiveCfg = Debug|Any CPU - {D9E125B3-8FFD-47CE-9C0E-FF5CEAF633AE}.Debug|x64.Build.0 = Debug|Any CPU - {D9E125B3-8FFD-47CE-9C0E-FF5CEAF633AE}.Debug|x86.ActiveCfg = Debug|Any CPU - {D9E125B3-8FFD-47CE-9C0E-FF5CEAF633AE}.Debug|x86.Build.0 = Debug|Any CPU - {D9E125B3-8FFD-47CE-9C0E-FF5CEAF633AE}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D9E125B3-8FFD-47CE-9C0E-FF5CEAF633AE}.Release|Any CPU.Build.0 = Release|Any CPU - {D9E125B3-8FFD-47CE-9C0E-FF5CEAF633AE}.Release|x64.ActiveCfg = Release|Any CPU - {D9E125B3-8FFD-47CE-9C0E-FF5CEAF633AE}.Release|x64.Build.0 = Release|Any CPU - {D9E125B3-8FFD-47CE-9C0E-FF5CEAF633AE}.Release|x86.ActiveCfg = Release|Any CPU - {D9E125B3-8FFD-47CE-9C0E-FF5CEAF633AE}.Release|x86.Build.0 = Release|Any CPU - {DA1687B8-10E4-4F50-B074-60D20912A9BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DA1687B8-10E4-4F50-B074-60D20912A9BD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DA1687B8-10E4-4F50-B074-60D20912A9BD}.Debug|x64.ActiveCfg = Debug|Any CPU - {DA1687B8-10E4-4F50-B074-60D20912A9BD}.Debug|x64.Build.0 = Debug|Any CPU - {DA1687B8-10E4-4F50-B074-60D20912A9BD}.Debug|x86.ActiveCfg = Debug|Any CPU - {DA1687B8-10E4-4F50-B074-60D20912A9BD}.Debug|x86.Build.0 = Debug|Any CPU - {DA1687B8-10E4-4F50-B074-60D20912A9BD}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DA1687B8-10E4-4F50-B074-60D20912A9BD}.Release|Any CPU.Build.0 = Release|Any CPU - {DA1687B8-10E4-4F50-B074-60D20912A9BD}.Release|x64.ActiveCfg = Release|Any CPU - {DA1687B8-10E4-4F50-B074-60D20912A9BD}.Release|x64.Build.0 = Release|Any CPU - {DA1687B8-10E4-4F50-B074-60D20912A9BD}.Release|x86.ActiveCfg = Release|Any CPU - {DA1687B8-10E4-4F50-B074-60D20912A9BD}.Release|x86.Build.0 = Release|Any CPU - {97CE175F-9290-479F-A6EB-EEF4C6816624}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {97CE175F-9290-479F-A6EB-EEF4C6816624}.Debug|Any CPU.Build.0 = Debug|Any CPU - {97CE175F-9290-479F-A6EB-EEF4C6816624}.Debug|x64.ActiveCfg = Debug|Any CPU - {97CE175F-9290-479F-A6EB-EEF4C6816624}.Debug|x64.Build.0 = Debug|Any CPU - {97CE175F-9290-479F-A6EB-EEF4C6816624}.Debug|x86.ActiveCfg = Debug|Any CPU - {97CE175F-9290-479F-A6EB-EEF4C6816624}.Debug|x86.Build.0 = Debug|Any CPU - {97CE175F-9290-479F-A6EB-EEF4C6816624}.Release|Any CPU.ActiveCfg = Release|Any CPU - {97CE175F-9290-479F-A6EB-EEF4C6816624}.Release|Any CPU.Build.0 = Release|Any CPU - {97CE175F-9290-479F-A6EB-EEF4C6816624}.Release|x64.ActiveCfg = Release|Any CPU - {97CE175F-9290-479F-A6EB-EEF4C6816624}.Release|x64.Build.0 = Release|Any CPU - {97CE175F-9290-479F-A6EB-EEF4C6816624}.Release|x86.ActiveCfg = Release|Any CPU - {97CE175F-9290-479F-A6EB-EEF4C6816624}.Release|x86.Build.0 = Release|Any CPU - {492ADBEC-D788-4039-A544-E1510D9328C1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {492ADBEC-D788-4039-A544-E1510D9328C1}.Debug|Any CPU.Build.0 = Debug|Any CPU - {492ADBEC-D788-4039-A544-E1510D9328C1}.Debug|x64.ActiveCfg = Debug|Any CPU - {492ADBEC-D788-4039-A544-E1510D9328C1}.Debug|x64.Build.0 = Debug|Any CPU - {492ADBEC-D788-4039-A544-E1510D9328C1}.Debug|x86.ActiveCfg = Debug|Any CPU - {492ADBEC-D788-4039-A544-E1510D9328C1}.Debug|x86.Build.0 = Debug|Any CPU - {492ADBEC-D788-4039-A544-E1510D9328C1}.Release|Any CPU.ActiveCfg = Release|Any CPU - {492ADBEC-D788-4039-A544-E1510D9328C1}.Release|Any CPU.Build.0 = Release|Any CPU - {492ADBEC-D788-4039-A544-E1510D9328C1}.Release|x64.ActiveCfg = Release|Any CPU - {492ADBEC-D788-4039-A544-E1510D9328C1}.Release|x64.Build.0 = Release|Any CPU - {492ADBEC-D788-4039-A544-E1510D9328C1}.Release|x86.ActiveCfg = Release|Any CPU - {492ADBEC-D788-4039-A544-E1510D9328C1}.Release|x86.Build.0 = Release|Any CPU - {B0A51484-8A24-4B9C-996B-415EB7733D56}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B0A51484-8A24-4B9C-996B-415EB7733D56}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B0A51484-8A24-4B9C-996B-415EB7733D56}.Debug|x64.ActiveCfg = Debug|Any CPU - {B0A51484-8A24-4B9C-996B-415EB7733D56}.Debug|x64.Build.0 = Debug|Any CPU - {B0A51484-8A24-4B9C-996B-415EB7733D56}.Debug|x86.ActiveCfg = Debug|Any CPU - {B0A51484-8A24-4B9C-996B-415EB7733D56}.Debug|x86.Build.0 = Debug|Any CPU - {B0A51484-8A24-4B9C-996B-415EB7733D56}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B0A51484-8A24-4B9C-996B-415EB7733D56}.Release|Any CPU.Build.0 = Release|Any CPU - {B0A51484-8A24-4B9C-996B-415EB7733D56}.Release|x64.ActiveCfg = Release|Any CPU - {B0A51484-8A24-4B9C-996B-415EB7733D56}.Release|x64.Build.0 = Release|Any CPU - {B0A51484-8A24-4B9C-996B-415EB7733D56}.Release|x86.ActiveCfg = Release|Any CPU - {B0A51484-8A24-4B9C-996B-415EB7733D56}.Release|x86.Build.0 = Release|Any CPU - {D809A2F0-0B7B-4B5D-B70C-05EFD3203301}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D809A2F0-0B7B-4B5D-B70C-05EFD3203301}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D809A2F0-0B7B-4B5D-B70C-05EFD3203301}.Debug|x64.ActiveCfg = Debug|Any CPU - {D809A2F0-0B7B-4B5D-B70C-05EFD3203301}.Debug|x64.Build.0 = Debug|Any CPU - {D809A2F0-0B7B-4B5D-B70C-05EFD3203301}.Debug|x86.ActiveCfg = Debug|Any CPU - {D809A2F0-0B7B-4B5D-B70C-05EFD3203301}.Debug|x86.Build.0 = Debug|Any CPU - {D809A2F0-0B7B-4B5D-B70C-05EFD3203301}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D809A2F0-0B7B-4B5D-B70C-05EFD3203301}.Release|Any CPU.Build.0 = Release|Any CPU - {D809A2F0-0B7B-4B5D-B70C-05EFD3203301}.Release|x64.ActiveCfg = Release|Any CPU - {D809A2F0-0B7B-4B5D-B70C-05EFD3203301}.Release|x64.Build.0 = Release|Any CPU - {D809A2F0-0B7B-4B5D-B70C-05EFD3203301}.Release|x86.ActiveCfg = Release|Any CPU - {D809A2F0-0B7B-4B5D-B70C-05EFD3203301}.Release|x86.Build.0 = Release|Any CPU - {365365A2-18A9-4EF8-A4CB-F096DAF078D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {365365A2-18A9-4EF8-A4CB-F096DAF078D9}.Debug|Any CPU.Build.0 = Debug|Any CPU - {365365A2-18A9-4EF8-A4CB-F096DAF078D9}.Debug|x64.ActiveCfg = Debug|Any CPU - {365365A2-18A9-4EF8-A4CB-F096DAF078D9}.Debug|x64.Build.0 = Debug|Any CPU - {365365A2-18A9-4EF8-A4CB-F096DAF078D9}.Debug|x86.ActiveCfg = Debug|Any CPU - {365365A2-18A9-4EF8-A4CB-F096DAF078D9}.Debug|x86.Build.0 = Debug|Any CPU - {365365A2-18A9-4EF8-A4CB-F096DAF078D9}.Release|Any CPU.ActiveCfg = Release|Any CPU - {365365A2-18A9-4EF8-A4CB-F096DAF078D9}.Release|Any CPU.Build.0 = Release|Any CPU - {365365A2-18A9-4EF8-A4CB-F096DAF078D9}.Release|x64.ActiveCfg = Release|Any CPU - {365365A2-18A9-4EF8-A4CB-F096DAF078D9}.Release|x64.Build.0 = Release|Any CPU - {365365A2-18A9-4EF8-A4CB-F096DAF078D9}.Release|x86.ActiveCfg = Release|Any CPU - {365365A2-18A9-4EF8-A4CB-F096DAF078D9}.Release|x86.Build.0 = Release|Any CPU - {92D23FF6-3C79-46CD-98ED-24DA16F8FDC3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {92D23FF6-3C79-46CD-98ED-24DA16F8FDC3}.Debug|Any CPU.Build.0 = Debug|Any CPU - {92D23FF6-3C79-46CD-98ED-24DA16F8FDC3}.Debug|x64.ActiveCfg = Debug|Any CPU - {92D23FF6-3C79-46CD-98ED-24DA16F8FDC3}.Debug|x64.Build.0 = Debug|Any CPU - {92D23FF6-3C79-46CD-98ED-24DA16F8FDC3}.Debug|x86.ActiveCfg = Debug|Any CPU - {92D23FF6-3C79-46CD-98ED-24DA16F8FDC3}.Debug|x86.Build.0 = Debug|Any CPU - {92D23FF6-3C79-46CD-98ED-24DA16F8FDC3}.Release|Any CPU.ActiveCfg = Release|Any CPU - {92D23FF6-3C79-46CD-98ED-24DA16F8FDC3}.Release|Any CPU.Build.0 = Release|Any CPU - {92D23FF6-3C79-46CD-98ED-24DA16F8FDC3}.Release|x64.ActiveCfg = Release|Any CPU - {92D23FF6-3C79-46CD-98ED-24DA16F8FDC3}.Release|x64.Build.0 = Release|Any CPU - {92D23FF6-3C79-46CD-98ED-24DA16F8FDC3}.Release|x86.ActiveCfg = Release|Any CPU - {92D23FF6-3C79-46CD-98ED-24DA16F8FDC3}.Release|x86.Build.0 = Release|Any CPU - {D8C72607-7E3E-4124-A065-A57F23E9F2BA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D8C72607-7E3E-4124-A065-A57F23E9F2BA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D8C72607-7E3E-4124-A065-A57F23E9F2BA}.Debug|x64.ActiveCfg = Debug|Any CPU - {D8C72607-7E3E-4124-A065-A57F23E9F2BA}.Debug|x64.Build.0 = Debug|Any CPU - {D8C72607-7E3E-4124-A065-A57F23E9F2BA}.Debug|x86.ActiveCfg = Debug|Any CPU - {D8C72607-7E3E-4124-A065-A57F23E9F2BA}.Debug|x86.Build.0 = Debug|Any CPU - {D8C72607-7E3E-4124-A065-A57F23E9F2BA}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D8C72607-7E3E-4124-A065-A57F23E9F2BA}.Release|Any CPU.Build.0 = Release|Any CPU - {D8C72607-7E3E-4124-A065-A57F23E9F2BA}.Release|x64.ActiveCfg = Release|Any CPU - {D8C72607-7E3E-4124-A065-A57F23E9F2BA}.Release|x64.Build.0 = Release|Any CPU - {D8C72607-7E3E-4124-A065-A57F23E9F2BA}.Release|x86.ActiveCfg = Release|Any CPU - {D8C72607-7E3E-4124-A065-A57F23E9F2BA}.Release|x86.Build.0 = Release|Any CPU - {4272499A-C424-41DF-B6B8-DF3C19416BE2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4272499A-C424-41DF-B6B8-DF3C19416BE2}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4272499A-C424-41DF-B6B8-DF3C19416BE2}.Debug|x64.ActiveCfg = Debug|Any CPU - {4272499A-C424-41DF-B6B8-DF3C19416BE2}.Debug|x64.Build.0 = Debug|Any CPU - {4272499A-C424-41DF-B6B8-DF3C19416BE2}.Debug|x86.ActiveCfg = Debug|Any CPU - {4272499A-C424-41DF-B6B8-DF3C19416BE2}.Debug|x86.Build.0 = Debug|Any CPU - {4272499A-C424-41DF-B6B8-DF3C19416BE2}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4272499A-C424-41DF-B6B8-DF3C19416BE2}.Release|Any CPU.Build.0 = Release|Any CPU - {4272499A-C424-41DF-B6B8-DF3C19416BE2}.Release|x64.ActiveCfg = Release|Any CPU - {4272499A-C424-41DF-B6B8-DF3C19416BE2}.Release|x64.Build.0 = Release|Any CPU - {4272499A-C424-41DF-B6B8-DF3C19416BE2}.Release|x86.ActiveCfg = Release|Any CPU - {4272499A-C424-41DF-B6B8-DF3C19416BE2}.Release|x86.Build.0 = Release|Any CPU - {E01CD19E-B0BE-4480-8B8E-3701DE862E62}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E01CD19E-B0BE-4480-8B8E-3701DE862E62}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E01CD19E-B0BE-4480-8B8E-3701DE862E62}.Debug|x64.ActiveCfg = Debug|Any CPU - {E01CD19E-B0BE-4480-8B8E-3701DE862E62}.Debug|x64.Build.0 = Debug|Any CPU - {E01CD19E-B0BE-4480-8B8E-3701DE862E62}.Debug|x86.ActiveCfg = Debug|Any CPU - {E01CD19E-B0BE-4480-8B8E-3701DE862E62}.Debug|x86.Build.0 = Debug|Any CPU - {E01CD19E-B0BE-4480-8B8E-3701DE862E62}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E01CD19E-B0BE-4480-8B8E-3701DE862E62}.Release|Any CPU.Build.0 = Release|Any CPU - {E01CD19E-B0BE-4480-8B8E-3701DE862E62}.Release|x64.ActiveCfg = Release|Any CPU - {E01CD19E-B0BE-4480-8B8E-3701DE862E62}.Release|x64.Build.0 = Release|Any CPU - {E01CD19E-B0BE-4480-8B8E-3701DE862E62}.Release|x86.ActiveCfg = Release|Any CPU - {E01CD19E-B0BE-4480-8B8E-3701DE862E62}.Release|x86.Build.0 = Release|Any CPU - {AA87CAA1-2456-4108-A02F-E16B9B8A98EE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {AA87CAA1-2456-4108-A02F-E16B9B8A98EE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {AA87CAA1-2456-4108-A02F-E16B9B8A98EE}.Debug|x64.ActiveCfg = Debug|Any CPU - {AA87CAA1-2456-4108-A02F-E16B9B8A98EE}.Debug|x64.Build.0 = Debug|Any CPU - {AA87CAA1-2456-4108-A02F-E16B9B8A98EE}.Debug|x86.ActiveCfg = Debug|Any CPU - {AA87CAA1-2456-4108-A02F-E16B9B8A98EE}.Debug|x86.Build.0 = Debug|Any CPU - {AA87CAA1-2456-4108-A02F-E16B9B8A98EE}.Release|Any CPU.ActiveCfg = Release|Any CPU - {AA87CAA1-2456-4108-A02F-E16B9B8A98EE}.Release|Any CPU.Build.0 = Release|Any CPU - {AA87CAA1-2456-4108-A02F-E16B9B8A98EE}.Release|x64.ActiveCfg = Release|Any CPU - {AA87CAA1-2456-4108-A02F-E16B9B8A98EE}.Release|x64.Build.0 = Release|Any CPU - {AA87CAA1-2456-4108-A02F-E16B9B8A98EE}.Release|x86.ActiveCfg = Release|Any CPU - {AA87CAA1-2456-4108-A02F-E16B9B8A98EE}.Release|x86.Build.0 = Release|Any CPU - {DC2F67CC-79DD-4F7C-AFD1-AC0D12B331C9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DC2F67CC-79DD-4F7C-AFD1-AC0D12B331C9}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DC2F67CC-79DD-4F7C-AFD1-AC0D12B331C9}.Debug|x64.ActiveCfg = Debug|Any CPU - {DC2F67CC-79DD-4F7C-AFD1-AC0D12B331C9}.Debug|x64.Build.0 = Debug|Any CPU - {DC2F67CC-79DD-4F7C-AFD1-AC0D12B331C9}.Debug|x86.ActiveCfg = Debug|Any CPU - {DC2F67CC-79DD-4F7C-AFD1-AC0D12B331C9}.Debug|x86.Build.0 = Debug|Any CPU - {DC2F67CC-79DD-4F7C-AFD1-AC0D12B331C9}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DC2F67CC-79DD-4F7C-AFD1-AC0D12B331C9}.Release|Any CPU.Build.0 = Release|Any CPU - {DC2F67CC-79DD-4F7C-AFD1-AC0D12B331C9}.Release|x64.ActiveCfg = Release|Any CPU - {DC2F67CC-79DD-4F7C-AFD1-AC0D12B331C9}.Release|x64.Build.0 = Release|Any CPU - {DC2F67CC-79DD-4F7C-AFD1-AC0D12B331C9}.Release|x86.ActiveCfg = Release|Any CPU - {DC2F67CC-79DD-4F7C-AFD1-AC0D12B331C9}.Release|x86.Build.0 = Release|Any CPU - {56DA124E-A37A-44DE-9DED-2764DDF0816C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {56DA124E-A37A-44DE-9DED-2764DDF0816C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {56DA124E-A37A-44DE-9DED-2764DDF0816C}.Debug|x64.ActiveCfg = Debug|Any CPU - {56DA124E-A37A-44DE-9DED-2764DDF0816C}.Debug|x64.Build.0 = Debug|Any CPU - {56DA124E-A37A-44DE-9DED-2764DDF0816C}.Debug|x86.ActiveCfg = Debug|Any CPU - {56DA124E-A37A-44DE-9DED-2764DDF0816C}.Debug|x86.Build.0 = Debug|Any CPU - {56DA124E-A37A-44DE-9DED-2764DDF0816C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {56DA124E-A37A-44DE-9DED-2764DDF0816C}.Release|Any CPU.Build.0 = Release|Any CPU - {56DA124E-A37A-44DE-9DED-2764DDF0816C}.Release|x64.ActiveCfg = Release|Any CPU - {56DA124E-A37A-44DE-9DED-2764DDF0816C}.Release|x64.Build.0 = Release|Any CPU - {56DA124E-A37A-44DE-9DED-2764DDF0816C}.Release|x86.ActiveCfg = Release|Any CPU - {56DA124E-A37A-44DE-9DED-2764DDF0816C}.Release|x86.Build.0 = Release|Any CPU - {527DB7FD-B118-4E49-B68A-55AAE9BFA109}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {527DB7FD-B118-4E49-B68A-55AAE9BFA109}.Debug|Any CPU.Build.0 = Debug|Any CPU - {527DB7FD-B118-4E49-B68A-55AAE9BFA109}.Debug|x64.ActiveCfg = Debug|Any CPU - {527DB7FD-B118-4E49-B68A-55AAE9BFA109}.Debug|x64.Build.0 = Debug|Any CPU - {527DB7FD-B118-4E49-B68A-55AAE9BFA109}.Debug|x86.ActiveCfg = Debug|Any CPU - {527DB7FD-B118-4E49-B68A-55AAE9BFA109}.Debug|x86.Build.0 = Debug|Any CPU - {527DB7FD-B118-4E49-B68A-55AAE9BFA109}.Release|Any CPU.ActiveCfg = Release|Any CPU - {527DB7FD-B118-4E49-B68A-55AAE9BFA109}.Release|Any CPU.Build.0 = Release|Any CPU - {527DB7FD-B118-4E49-B68A-55AAE9BFA109}.Release|x64.ActiveCfg = Release|Any CPU - {527DB7FD-B118-4E49-B68A-55AAE9BFA109}.Release|x64.Build.0 = Release|Any CPU - {527DB7FD-B118-4E49-B68A-55AAE9BFA109}.Release|x86.ActiveCfg = Release|Any CPU - {527DB7FD-B118-4E49-B68A-55AAE9BFA109}.Release|x86.Build.0 = Release|Any CPU - {BB6E57A6-5434-46D4-AA09-72DC29794506}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {BB6E57A6-5434-46D4-AA09-72DC29794506}.Debug|Any CPU.Build.0 = Debug|Any CPU - {BB6E57A6-5434-46D4-AA09-72DC29794506}.Debug|x64.ActiveCfg = Debug|Any CPU - {BB6E57A6-5434-46D4-AA09-72DC29794506}.Debug|x64.Build.0 = Debug|Any CPU - {BB6E57A6-5434-46D4-AA09-72DC29794506}.Debug|x86.ActiveCfg = Debug|Any CPU - {BB6E57A6-5434-46D4-AA09-72DC29794506}.Debug|x86.Build.0 = Debug|Any CPU - {BB6E57A6-5434-46D4-AA09-72DC29794506}.Release|Any CPU.ActiveCfg = Release|Any CPU - {BB6E57A6-5434-46D4-AA09-72DC29794506}.Release|Any CPU.Build.0 = Release|Any CPU - {BB6E57A6-5434-46D4-AA09-72DC29794506}.Release|x64.ActiveCfg = Release|Any CPU - {BB6E57A6-5434-46D4-AA09-72DC29794506}.Release|x64.Build.0 = Release|Any CPU - {BB6E57A6-5434-46D4-AA09-72DC29794506}.Release|x86.ActiveCfg = Release|Any CPU - {BB6E57A6-5434-46D4-AA09-72DC29794506}.Release|x86.Build.0 = Release|Any CPU - {557608E1-1DF3-4A24-80EB-C557C676A9CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {557608E1-1DF3-4A24-80EB-C557C676A9CE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {557608E1-1DF3-4A24-80EB-C557C676A9CE}.Debug|x64.ActiveCfg = Debug|Any CPU - {557608E1-1DF3-4A24-80EB-C557C676A9CE}.Debug|x64.Build.0 = Debug|Any CPU - {557608E1-1DF3-4A24-80EB-C557C676A9CE}.Debug|x86.ActiveCfg = Debug|Any CPU - {557608E1-1DF3-4A24-80EB-C557C676A9CE}.Debug|x86.Build.0 = Debug|Any CPU - {557608E1-1DF3-4A24-80EB-C557C676A9CE}.Release|Any CPU.ActiveCfg = Release|Any CPU - {557608E1-1DF3-4A24-80EB-C557C676A9CE}.Release|Any CPU.Build.0 = Release|Any CPU - {557608E1-1DF3-4A24-80EB-C557C676A9CE}.Release|x64.ActiveCfg = Release|Any CPU - {557608E1-1DF3-4A24-80EB-C557C676A9CE}.Release|x64.Build.0 = Release|Any CPU - {557608E1-1DF3-4A24-80EB-C557C676A9CE}.Release|x86.ActiveCfg = Release|Any CPU - {557608E1-1DF3-4A24-80EB-C557C676A9CE}.Release|x86.Build.0 = Release|Any CPU - {9241EDB4-8FCE-4F8E-9727-C9557C59907C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9241EDB4-8FCE-4F8E-9727-C9557C59907C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9241EDB4-8FCE-4F8E-9727-C9557C59907C}.Debug|x64.ActiveCfg = Debug|Any CPU - {9241EDB4-8FCE-4F8E-9727-C9557C59907C}.Debug|x64.Build.0 = Debug|Any CPU - {9241EDB4-8FCE-4F8E-9727-C9557C59907C}.Debug|x86.ActiveCfg = Debug|Any CPU - {9241EDB4-8FCE-4F8E-9727-C9557C59907C}.Debug|x86.Build.0 = Debug|Any CPU - {9241EDB4-8FCE-4F8E-9727-C9557C59907C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9241EDB4-8FCE-4F8E-9727-C9557C59907C}.Release|Any CPU.Build.0 = Release|Any CPU - {9241EDB4-8FCE-4F8E-9727-C9557C59907C}.Release|x64.ActiveCfg = Release|Any CPU - {9241EDB4-8FCE-4F8E-9727-C9557C59907C}.Release|x64.Build.0 = Release|Any CPU - {9241EDB4-8FCE-4F8E-9727-C9557C59907C}.Release|x86.ActiveCfg = Release|Any CPU - {9241EDB4-8FCE-4F8E-9727-C9557C59907C}.Release|x86.Build.0 = Release|Any CPU - {3FAF725B-A628-4531-9F61-499660CD4347}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3FAF725B-A628-4531-9F61-499660CD4347}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3FAF725B-A628-4531-9F61-499660CD4347}.Debug|x64.ActiveCfg = Debug|Any CPU - {3FAF725B-A628-4531-9F61-499660CD4347}.Debug|x64.Build.0 = Debug|Any CPU - {3FAF725B-A628-4531-9F61-499660CD4347}.Debug|x86.ActiveCfg = Debug|Any CPU - {3FAF725B-A628-4531-9F61-499660CD4347}.Debug|x86.Build.0 = Debug|Any CPU - {3FAF725B-A628-4531-9F61-499660CD4347}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3FAF725B-A628-4531-9F61-499660CD4347}.Release|Any CPU.Build.0 = Release|Any CPU - {3FAF725B-A628-4531-9F61-499660CD4347}.Release|x64.ActiveCfg = Release|Any CPU - {3FAF725B-A628-4531-9F61-499660CD4347}.Release|x64.Build.0 = Release|Any CPU - {3FAF725B-A628-4531-9F61-499660CD4347}.Release|x86.ActiveCfg = Release|Any CPU - {3FAF725B-A628-4531-9F61-499660CD4347}.Release|x86.Build.0 = Release|Any CPU - {04262990-929C-42BF-85A9-21C25FA95617}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {04262990-929C-42BF-85A9-21C25FA95617}.Debug|Any CPU.Build.0 = Debug|Any CPU - {04262990-929C-42BF-85A9-21C25FA95617}.Debug|x64.ActiveCfg = Debug|Any CPU - {04262990-929C-42BF-85A9-21C25FA95617}.Debug|x64.Build.0 = Debug|Any CPU - {04262990-929C-42BF-85A9-21C25FA95617}.Debug|x86.ActiveCfg = Debug|Any CPU - {04262990-929C-42BF-85A9-21C25FA95617}.Debug|x86.Build.0 = Debug|Any CPU - {04262990-929C-42BF-85A9-21C25FA95617}.Release|Any CPU.ActiveCfg = Release|Any CPU - {04262990-929C-42BF-85A9-21C25FA95617}.Release|Any CPU.Build.0 = Release|Any CPU - {04262990-929C-42BF-85A9-21C25FA95617}.Release|x64.ActiveCfg = Release|Any CPU - {04262990-929C-42BF-85A9-21C25FA95617}.Release|x64.Build.0 = Release|Any CPU - {04262990-929C-42BF-85A9-21C25FA95617}.Release|x86.ActiveCfg = Release|Any CPU - {04262990-929C-42BF-85A9-21C25FA95617}.Release|x86.Build.0 = Release|Any CPU - {DC47C40A-FC38-44E4-94A4-ADE794E76309}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DC47C40A-FC38-44E4-94A4-ADE794E76309}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DC47C40A-FC38-44E4-94A4-ADE794E76309}.Debug|x64.ActiveCfg = Debug|Any CPU - {DC47C40A-FC38-44E4-94A4-ADE794E76309}.Debug|x64.Build.0 = Debug|Any CPU - {DC47C40A-FC38-44E4-94A4-ADE794E76309}.Debug|x86.ActiveCfg = Debug|Any CPU - {DC47C40A-FC38-44E4-94A4-ADE794E76309}.Debug|x86.Build.0 = Debug|Any CPU - {DC47C40A-FC38-44E4-94A4-ADE794E76309}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DC47C40A-FC38-44E4-94A4-ADE794E76309}.Release|Any CPU.Build.0 = Release|Any CPU - {DC47C40A-FC38-44E4-94A4-ADE794E76309}.Release|x64.ActiveCfg = Release|Any CPU - {DC47C40A-FC38-44E4-94A4-ADE794E76309}.Release|x64.Build.0 = Release|Any CPU - {DC47C40A-FC38-44E4-94A4-ADE794E76309}.Release|x86.ActiveCfg = Release|Any CPU - {DC47C40A-FC38-44E4-94A4-ADE794E76309}.Release|x86.Build.0 = Release|Any CPU - {ED210157-461B-45BB-9D86-B81A62792C30}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {ED210157-461B-45BB-9D86-B81A62792C30}.Debug|Any CPU.Build.0 = Debug|Any CPU - {ED210157-461B-45BB-9D86-B81A62792C30}.Debug|x64.ActiveCfg = Debug|Any CPU - {ED210157-461B-45BB-9D86-B81A62792C30}.Debug|x64.Build.0 = Debug|Any CPU - {ED210157-461B-45BB-9D86-B81A62792C30}.Debug|x86.ActiveCfg = Debug|Any CPU - {ED210157-461B-45BB-9D86-B81A62792C30}.Debug|x86.Build.0 = Debug|Any CPU - {ED210157-461B-45BB-9D86-B81A62792C30}.Release|Any CPU.ActiveCfg = Release|Any CPU - {ED210157-461B-45BB-9D86-B81A62792C30}.Release|Any CPU.Build.0 = Release|Any CPU - {ED210157-461B-45BB-9D86-B81A62792C30}.Release|x64.ActiveCfg = Release|Any CPU - {ED210157-461B-45BB-9D86-B81A62792C30}.Release|x64.Build.0 = Release|Any CPU - {ED210157-461B-45BB-9D86-B81A62792C30}.Release|x86.ActiveCfg = Release|Any CPU - {ED210157-461B-45BB-9D86-B81A62792C30}.Release|x86.Build.0 = Release|Any CPU - {DA137BD4-F7F1-4D53-855F-5EC40CEA36B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DA137BD4-F7F1-4D53-855F-5EC40CEA36B0}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DA137BD4-F7F1-4D53-855F-5EC40CEA36B0}.Debug|x64.ActiveCfg = Debug|Any CPU - {DA137BD4-F7F1-4D53-855F-5EC40CEA36B0}.Debug|x64.Build.0 = Debug|Any CPU - {DA137BD4-F7F1-4D53-855F-5EC40CEA36B0}.Debug|x86.ActiveCfg = Debug|Any CPU - {DA137BD4-F7F1-4D53-855F-5EC40CEA36B0}.Debug|x86.Build.0 = Debug|Any CPU - {DA137BD4-F7F1-4D53-855F-5EC40CEA36B0}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DA137BD4-F7F1-4D53-855F-5EC40CEA36B0}.Release|Any CPU.Build.0 = Release|Any CPU - {DA137BD4-F7F1-4D53-855F-5EC40CEA36B0}.Release|x64.ActiveCfg = Release|Any CPU - {DA137BD4-F7F1-4D53-855F-5EC40CEA36B0}.Release|x64.Build.0 = Release|Any CPU - {DA137BD4-F7F1-4D53-855F-5EC40CEA36B0}.Release|x86.ActiveCfg = Release|Any CPU - {DA137BD4-F7F1-4D53-855F-5EC40CEA36B0}.Release|x86.Build.0 = Release|Any CPU - {0CDAB70B-71DC-43BE-ACB7-AD2EE3541FFB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0CDAB70B-71DC-43BE-ACB7-AD2EE3541FFB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0CDAB70B-71DC-43BE-ACB7-AD2EE3541FFB}.Debug|x64.ActiveCfg = Debug|Any CPU - {0CDAB70B-71DC-43BE-ACB7-AD2EE3541FFB}.Debug|x64.Build.0 = Debug|Any CPU - {0CDAB70B-71DC-43BE-ACB7-AD2EE3541FFB}.Debug|x86.ActiveCfg = Debug|Any CPU - {0CDAB70B-71DC-43BE-ACB7-AD2EE3541FFB}.Debug|x86.Build.0 = Debug|Any CPU - {0CDAB70B-71DC-43BE-ACB7-AD2EE3541FFB}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0CDAB70B-71DC-43BE-ACB7-AD2EE3541FFB}.Release|Any CPU.Build.0 = Release|Any CPU - {0CDAB70B-71DC-43BE-ACB7-AD2EE3541FFB}.Release|x64.ActiveCfg = Release|Any CPU - {0CDAB70B-71DC-43BE-ACB7-AD2EE3541FFB}.Release|x64.Build.0 = Release|Any CPU - {0CDAB70B-71DC-43BE-ACB7-AD2EE3541FFB}.Release|x86.ActiveCfg = Release|Any CPU - {0CDAB70B-71DC-43BE-ACB7-AD2EE3541FFB}.Release|x86.Build.0 = Release|Any CPU - {F88118E1-6F4A-4F89-B047-5FFD2889B9F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F88118E1-6F4A-4F89-B047-5FFD2889B9F0}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F88118E1-6F4A-4F89-B047-5FFD2889B9F0}.Debug|x64.ActiveCfg = Debug|Any CPU - {F88118E1-6F4A-4F89-B047-5FFD2889B9F0}.Debug|x64.Build.0 = Debug|Any CPU - {F88118E1-6F4A-4F89-B047-5FFD2889B9F0}.Debug|x86.ActiveCfg = Debug|Any CPU - {F88118E1-6F4A-4F89-B047-5FFD2889B9F0}.Debug|x86.Build.0 = Debug|Any CPU - {F88118E1-6F4A-4F89-B047-5FFD2889B9F0}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F88118E1-6F4A-4F89-B047-5FFD2889B9F0}.Release|Any CPU.Build.0 = Release|Any CPU - {F88118E1-6F4A-4F89-B047-5FFD2889B9F0}.Release|x64.ActiveCfg = Release|Any CPU - {F88118E1-6F4A-4F89-B047-5FFD2889B9F0}.Release|x64.Build.0 = Release|Any CPU - {F88118E1-6F4A-4F89-B047-5FFD2889B9F0}.Release|x86.ActiveCfg = Release|Any CPU - {F88118E1-6F4A-4F89-B047-5FFD2889B9F0}.Release|x86.Build.0 = Release|Any CPU - {74D21785-2FAB-4266-B7C4-E311EC8EE0DF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {74D21785-2FAB-4266-B7C4-E311EC8EE0DF}.Debug|Any CPU.Build.0 = Debug|Any CPU - {74D21785-2FAB-4266-B7C4-E311EC8EE0DF}.Debug|x64.ActiveCfg = Debug|Any CPU - {74D21785-2FAB-4266-B7C4-E311EC8EE0DF}.Debug|x64.Build.0 = Debug|Any CPU - {74D21785-2FAB-4266-B7C4-E311EC8EE0DF}.Debug|x86.ActiveCfg = Debug|Any CPU - {74D21785-2FAB-4266-B7C4-E311EC8EE0DF}.Debug|x86.Build.0 = Debug|Any CPU - {74D21785-2FAB-4266-B7C4-E311EC8EE0DF}.Release|Any CPU.ActiveCfg = Release|Any CPU - {74D21785-2FAB-4266-B7C4-E311EC8EE0DF}.Release|Any CPU.Build.0 = Release|Any CPU - {74D21785-2FAB-4266-B7C4-E311EC8EE0DF}.Release|x64.ActiveCfg = Release|Any CPU - {74D21785-2FAB-4266-B7C4-E311EC8EE0DF}.Release|x64.Build.0 = Release|Any CPU - {74D21785-2FAB-4266-B7C4-E311EC8EE0DF}.Release|x86.ActiveCfg = Release|Any CPU - {74D21785-2FAB-4266-B7C4-E311EC8EE0DF}.Release|x86.Build.0 = Release|Any CPU - {E4C01A3F-D3C1-4639-A6A9-930E918843DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E4C01A3F-D3C1-4639-A6A9-930E918843DD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E4C01A3F-D3C1-4639-A6A9-930E918843DD}.Debug|x64.ActiveCfg = Debug|Any CPU - {E4C01A3F-D3C1-4639-A6A9-930E918843DD}.Debug|x64.Build.0 = Debug|Any CPU - {E4C01A3F-D3C1-4639-A6A9-930E918843DD}.Debug|x86.ActiveCfg = Debug|Any CPU - {E4C01A3F-D3C1-4639-A6A9-930E918843DD}.Debug|x86.Build.0 = Debug|Any CPU - {E4C01A3F-D3C1-4639-A6A9-930E918843DD}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E4C01A3F-D3C1-4639-A6A9-930E918843DD}.Release|Any CPU.Build.0 = Release|Any CPU - {E4C01A3F-D3C1-4639-A6A9-930E918843DD}.Release|x64.ActiveCfg = Release|Any CPU - {E4C01A3F-D3C1-4639-A6A9-930E918843DD}.Release|x64.Build.0 = Release|Any CPU - {E4C01A3F-D3C1-4639-A6A9-930E918843DD}.Release|x86.ActiveCfg = Release|Any CPU - {E4C01A3F-D3C1-4639-A6A9-930E918843DD}.Release|x86.Build.0 = Release|Any CPU - {DE297C91-B3E9-4C6F-B74D-0AF9EFEBF684}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DE297C91-B3E9-4C6F-B74D-0AF9EFEBF684}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DE297C91-B3E9-4C6F-B74D-0AF9EFEBF684}.Debug|x64.ActiveCfg = Debug|Any CPU - {DE297C91-B3E9-4C6F-B74D-0AF9EFEBF684}.Debug|x64.Build.0 = Debug|Any CPU - {DE297C91-B3E9-4C6F-B74D-0AF9EFEBF684}.Debug|x86.ActiveCfg = Debug|Any CPU - {DE297C91-B3E9-4C6F-B74D-0AF9EFEBF684}.Debug|x86.Build.0 = Debug|Any CPU - {DE297C91-B3E9-4C6F-B74D-0AF9EFEBF684}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DE297C91-B3E9-4C6F-B74D-0AF9EFEBF684}.Release|Any CPU.Build.0 = Release|Any CPU - {DE297C91-B3E9-4C6F-B74D-0AF9EFEBF684}.Release|x64.ActiveCfg = Release|Any CPU - {DE297C91-B3E9-4C6F-B74D-0AF9EFEBF684}.Release|x64.Build.0 = Release|Any CPU - {DE297C91-B3E9-4C6F-B74D-0AF9EFEBF684}.Release|x86.ActiveCfg = Release|Any CPU - {DE297C91-B3E9-4C6F-B74D-0AF9EFEBF684}.Release|x86.Build.0 = Release|Any CPU - {956F540A-3CDA-4913-9373-1A4E8A93BDD8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {956F540A-3CDA-4913-9373-1A4E8A93BDD8}.Debug|Any CPU.Build.0 = Debug|Any CPU - {956F540A-3CDA-4913-9373-1A4E8A93BDD8}.Debug|x64.ActiveCfg = Debug|Any CPU - {956F540A-3CDA-4913-9373-1A4E8A93BDD8}.Debug|x64.Build.0 = Debug|Any CPU - {956F540A-3CDA-4913-9373-1A4E8A93BDD8}.Debug|x86.ActiveCfg = Debug|Any CPU - {956F540A-3CDA-4913-9373-1A4E8A93BDD8}.Debug|x86.Build.0 = Debug|Any CPU - {956F540A-3CDA-4913-9373-1A4E8A93BDD8}.Release|Any CPU.ActiveCfg = Release|Any CPU - {956F540A-3CDA-4913-9373-1A4E8A93BDD8}.Release|Any CPU.Build.0 = Release|Any CPU - {956F540A-3CDA-4913-9373-1A4E8A93BDD8}.Release|x64.ActiveCfg = Release|Any CPU - {956F540A-3CDA-4913-9373-1A4E8A93BDD8}.Release|x64.Build.0 = Release|Any CPU - {956F540A-3CDA-4913-9373-1A4E8A93BDD8}.Release|x86.ActiveCfg = Release|Any CPU - {956F540A-3CDA-4913-9373-1A4E8A93BDD8}.Release|x86.Build.0 = Release|Any CPU - {B13CDE69-ED22-4664-AAD7-686ED8CD5E88}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B13CDE69-ED22-4664-AAD7-686ED8CD5E88}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B13CDE69-ED22-4664-AAD7-686ED8CD5E88}.Debug|x64.ActiveCfg = Debug|Any CPU - {B13CDE69-ED22-4664-AAD7-686ED8CD5E88}.Debug|x64.Build.0 = Debug|Any CPU - {B13CDE69-ED22-4664-AAD7-686ED8CD5E88}.Debug|x86.ActiveCfg = Debug|Any CPU - {B13CDE69-ED22-4664-AAD7-686ED8CD5E88}.Debug|x86.Build.0 = Debug|Any CPU - {B13CDE69-ED22-4664-AAD7-686ED8CD5E88}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B13CDE69-ED22-4664-AAD7-686ED8CD5E88}.Release|Any CPU.Build.0 = Release|Any CPU - {B13CDE69-ED22-4664-AAD7-686ED8CD5E88}.Release|x64.ActiveCfg = Release|Any CPU - {B13CDE69-ED22-4664-AAD7-686ED8CD5E88}.Release|x64.Build.0 = Release|Any CPU - {B13CDE69-ED22-4664-AAD7-686ED8CD5E88}.Release|x86.ActiveCfg = Release|Any CPU - {B13CDE69-ED22-4664-AAD7-686ED8CD5E88}.Release|x86.Build.0 = Release|Any CPU - {A5C132FB-1E03-4DA9-8D05-80755ED1D0ED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A5C132FB-1E03-4DA9-8D05-80755ED1D0ED}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A5C132FB-1E03-4DA9-8D05-80755ED1D0ED}.Debug|x64.ActiveCfg = Debug|Any CPU - {A5C132FB-1E03-4DA9-8D05-80755ED1D0ED}.Debug|x64.Build.0 = Debug|Any CPU - {A5C132FB-1E03-4DA9-8D05-80755ED1D0ED}.Debug|x86.ActiveCfg = Debug|Any CPU - {A5C132FB-1E03-4DA9-8D05-80755ED1D0ED}.Debug|x86.Build.0 = Debug|Any CPU - {A5C132FB-1E03-4DA9-8D05-80755ED1D0ED}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A5C132FB-1E03-4DA9-8D05-80755ED1D0ED}.Release|Any CPU.Build.0 = Release|Any CPU - {A5C132FB-1E03-4DA9-8D05-80755ED1D0ED}.Release|x64.ActiveCfg = Release|Any CPU - {A5C132FB-1E03-4DA9-8D05-80755ED1D0ED}.Release|x64.Build.0 = Release|Any CPU - {A5C132FB-1E03-4DA9-8D05-80755ED1D0ED}.Release|x86.ActiveCfg = Release|Any CPU - {A5C132FB-1E03-4DA9-8D05-80755ED1D0ED}.Release|x86.Build.0 = Release|Any CPU - {173D84A3-0F37-480F-AC0F-7E2DBBE32B28}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {173D84A3-0F37-480F-AC0F-7E2DBBE32B28}.Debug|Any CPU.Build.0 = Debug|Any CPU - {173D84A3-0F37-480F-AC0F-7E2DBBE32B28}.Debug|x64.ActiveCfg = Debug|Any CPU - {173D84A3-0F37-480F-AC0F-7E2DBBE32B28}.Debug|x64.Build.0 = Debug|Any CPU - {173D84A3-0F37-480F-AC0F-7E2DBBE32B28}.Debug|x86.ActiveCfg = Debug|Any CPU - {173D84A3-0F37-480F-AC0F-7E2DBBE32B28}.Debug|x86.Build.0 = Debug|Any CPU - {173D84A3-0F37-480F-AC0F-7E2DBBE32B28}.Release|Any CPU.ActiveCfg = Release|Any CPU - {173D84A3-0F37-480F-AC0F-7E2DBBE32B28}.Release|Any CPU.Build.0 = Release|Any CPU - {173D84A3-0F37-480F-AC0F-7E2DBBE32B28}.Release|x64.ActiveCfg = Release|Any CPU - {173D84A3-0F37-480F-AC0F-7E2DBBE32B28}.Release|x64.Build.0 = Release|Any CPU - {173D84A3-0F37-480F-AC0F-7E2DBBE32B28}.Release|x86.ActiveCfg = Release|Any CPU - {173D84A3-0F37-480F-AC0F-7E2DBBE32B28}.Release|x86.Build.0 = Release|Any CPU - {4664276D-606A-4BB3-873A-9EE84FB22877}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4664276D-606A-4BB3-873A-9EE84FB22877}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4664276D-606A-4BB3-873A-9EE84FB22877}.Debug|x64.ActiveCfg = Debug|Any CPU - {4664276D-606A-4BB3-873A-9EE84FB22877}.Debug|x64.Build.0 = Debug|Any CPU - {4664276D-606A-4BB3-873A-9EE84FB22877}.Debug|x86.ActiveCfg = Debug|Any CPU - {4664276D-606A-4BB3-873A-9EE84FB22877}.Debug|x86.Build.0 = Debug|Any CPU - {4664276D-606A-4BB3-873A-9EE84FB22877}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4664276D-606A-4BB3-873A-9EE84FB22877}.Release|Any CPU.Build.0 = Release|Any CPU - {4664276D-606A-4BB3-873A-9EE84FB22877}.Release|x64.ActiveCfg = Release|Any CPU - {4664276D-606A-4BB3-873A-9EE84FB22877}.Release|x64.Build.0 = Release|Any CPU - {4664276D-606A-4BB3-873A-9EE84FB22877}.Release|x86.ActiveCfg = Release|Any CPU - {4664276D-606A-4BB3-873A-9EE84FB22877}.Release|x86.Build.0 = Release|Any CPU - {BBF37AF9-8290-4B70-8BA8-0F6017B3B620}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {BBF37AF9-8290-4B70-8BA8-0F6017B3B620}.Debug|Any CPU.Build.0 = Debug|Any CPU - {BBF37AF9-8290-4B70-8BA8-0F6017B3B620}.Debug|x64.ActiveCfg = Debug|Any CPU - {BBF37AF9-8290-4B70-8BA8-0F6017B3B620}.Debug|x64.Build.0 = Debug|Any CPU - {BBF37AF9-8290-4B70-8BA8-0F6017B3B620}.Debug|x86.ActiveCfg = Debug|Any CPU - {BBF37AF9-8290-4B70-8BA8-0F6017B3B620}.Debug|x86.Build.0 = Debug|Any CPU - {BBF37AF9-8290-4B70-8BA8-0F6017B3B620}.Release|Any CPU.ActiveCfg = Release|Any CPU - {BBF37AF9-8290-4B70-8BA8-0F6017B3B620}.Release|Any CPU.Build.0 = Release|Any CPU - {BBF37AF9-8290-4B70-8BA8-0F6017B3B620}.Release|x64.ActiveCfg = Release|Any CPU - {BBF37AF9-8290-4B70-8BA8-0F6017B3B620}.Release|x64.Build.0 = Release|Any CPU - {BBF37AF9-8290-4B70-8BA8-0F6017B3B620}.Release|x86.ActiveCfg = Release|Any CPU - {BBF37AF9-8290-4B70-8BA8-0F6017B3B620}.Release|x86.Build.0 = Release|Any CPU - {CD0EF85C-4187-4515-A355-E5A0D4485F40}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CD0EF85C-4187-4515-A355-E5A0D4485F40}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CD0EF85C-4187-4515-A355-E5A0D4485F40}.Debug|x64.ActiveCfg = Debug|Any CPU - {CD0EF85C-4187-4515-A355-E5A0D4485F40}.Debug|x64.Build.0 = Debug|Any CPU - {CD0EF85C-4187-4515-A355-E5A0D4485F40}.Debug|x86.ActiveCfg = Debug|Any CPU - {CD0EF85C-4187-4515-A355-E5A0D4485F40}.Debug|x86.Build.0 = Debug|Any CPU - {CD0EF85C-4187-4515-A355-E5A0D4485F40}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CD0EF85C-4187-4515-A355-E5A0D4485F40}.Release|Any CPU.Build.0 = Release|Any CPU - {CD0EF85C-4187-4515-A355-E5A0D4485F40}.Release|x64.ActiveCfg = Release|Any CPU - {CD0EF85C-4187-4515-A355-E5A0D4485F40}.Release|x64.Build.0 = Release|Any CPU - {CD0EF85C-4187-4515-A355-E5A0D4485F40}.Release|x86.ActiveCfg = Release|Any CPU - {CD0EF85C-4187-4515-A355-E5A0D4485F40}.Release|x86.Build.0 = Release|Any CPU - {F31E8118-014E-4CCE-8A48-5282F7B9BB3E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F31E8118-014E-4CCE-8A48-5282F7B9BB3E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F31E8118-014E-4CCE-8A48-5282F7B9BB3E}.Debug|x64.ActiveCfg = Debug|Any CPU - {F31E8118-014E-4CCE-8A48-5282F7B9BB3E}.Debug|x64.Build.0 = Debug|Any CPU - {F31E8118-014E-4CCE-8A48-5282F7B9BB3E}.Debug|x86.ActiveCfg = Debug|Any CPU - {F31E8118-014E-4CCE-8A48-5282F7B9BB3E}.Debug|x86.Build.0 = Debug|Any CPU - {F31E8118-014E-4CCE-8A48-5282F7B9BB3E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F31E8118-014E-4CCE-8A48-5282F7B9BB3E}.Release|Any CPU.Build.0 = Release|Any CPU - {F31E8118-014E-4CCE-8A48-5282F7B9BB3E}.Release|x64.ActiveCfg = Release|Any CPU - {F31E8118-014E-4CCE-8A48-5282F7B9BB3E}.Release|x64.Build.0 = Release|Any CPU - {F31E8118-014E-4CCE-8A48-5282F7B9BB3E}.Release|x86.ActiveCfg = Release|Any CPU - {F31E8118-014E-4CCE-8A48-5282F7B9BB3E}.Release|x86.Build.0 = Release|Any CPU - {B70F90C7-2696-4050-B24E-BF0308F4E059}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B70F90C7-2696-4050-B24E-BF0308F4E059}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B70F90C7-2696-4050-B24E-BF0308F4E059}.Debug|x64.ActiveCfg = Debug|Any CPU - {B70F90C7-2696-4050-B24E-BF0308F4E059}.Debug|x64.Build.0 = Debug|Any CPU - {B70F90C7-2696-4050-B24E-BF0308F4E059}.Debug|x86.ActiveCfg = Debug|Any CPU - {B70F90C7-2696-4050-B24E-BF0308F4E059}.Debug|x86.Build.0 = Debug|Any CPU - {B70F90C7-2696-4050-B24E-BF0308F4E059}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B70F90C7-2696-4050-B24E-BF0308F4E059}.Release|Any CPU.Build.0 = Release|Any CPU - {B70F90C7-2696-4050-B24E-BF0308F4E059}.Release|x64.ActiveCfg = Release|Any CPU - {B70F90C7-2696-4050-B24E-BF0308F4E059}.Release|x64.Build.0 = Release|Any CPU - {B70F90C7-2696-4050-B24E-BF0308F4E059}.Release|x86.ActiveCfg = Release|Any CPU - {B70F90C7-2696-4050-B24E-BF0308F4E059}.Release|x86.Build.0 = Release|Any CPU - {A5617A9D-C71E-44DE-936C-27611EB40A02}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A5617A9D-C71E-44DE-936C-27611EB40A02}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A5617A9D-C71E-44DE-936C-27611EB40A02}.Debug|x64.ActiveCfg = Debug|Any CPU - {A5617A9D-C71E-44DE-936C-27611EB40A02}.Debug|x64.Build.0 = Debug|Any CPU - {A5617A9D-C71E-44DE-936C-27611EB40A02}.Debug|x86.ActiveCfg = Debug|Any CPU - {A5617A9D-C71E-44DE-936C-27611EB40A02}.Debug|x86.Build.0 = Debug|Any CPU - {A5617A9D-C71E-44DE-936C-27611EB40A02}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A5617A9D-C71E-44DE-936C-27611EB40A02}.Release|Any CPU.Build.0 = Release|Any CPU - {A5617A9D-C71E-44DE-936C-27611EB40A02}.Release|x64.ActiveCfg = Release|Any CPU - {A5617A9D-C71E-44DE-936C-27611EB40A02}.Release|x64.Build.0 = Release|Any CPU - {A5617A9D-C71E-44DE-936C-27611EB40A02}.Release|x86.ActiveCfg = Release|Any CPU - {A5617A9D-C71E-44DE-936C-27611EB40A02}.Release|x86.Build.0 = Release|Any CPU - {D141CFEE-D10A-406B-8963-F86FA13732E3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D141CFEE-D10A-406B-8963-F86FA13732E3}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D141CFEE-D10A-406B-8963-F86FA13732E3}.Debug|x64.ActiveCfg = Debug|Any CPU - {D141CFEE-D10A-406B-8963-F86FA13732E3}.Debug|x64.Build.0 = Debug|Any CPU - {D141CFEE-D10A-406B-8963-F86FA13732E3}.Debug|x86.ActiveCfg = Debug|Any CPU - {D141CFEE-D10A-406B-8963-F86FA13732E3}.Debug|x86.Build.0 = Debug|Any CPU - {D141CFEE-D10A-406B-8963-F86FA13732E3}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D141CFEE-D10A-406B-8963-F86FA13732E3}.Release|Any CPU.Build.0 = Release|Any CPU - {D141CFEE-D10A-406B-8963-F86FA13732E3}.Release|x64.ActiveCfg = Release|Any CPU - {D141CFEE-D10A-406B-8963-F86FA13732E3}.Release|x64.Build.0 = Release|Any CPU - {D141CFEE-D10A-406B-8963-F86FA13732E3}.Release|x86.ActiveCfg = Release|Any CPU - {D141CFEE-D10A-406B-8963-F86FA13732E3}.Release|x86.Build.0 = Release|Any CPU - {F2E27E1C-2E47-42C1-9AC7-36265A381717}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F2E27E1C-2E47-42C1-9AC7-36265A381717}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F2E27E1C-2E47-42C1-9AC7-36265A381717}.Debug|x64.ActiveCfg = Debug|Any CPU - {F2E27E1C-2E47-42C1-9AC7-36265A381717}.Debug|x64.Build.0 = Debug|Any CPU - {F2E27E1C-2E47-42C1-9AC7-36265A381717}.Debug|x86.ActiveCfg = Debug|Any CPU - {F2E27E1C-2E47-42C1-9AC7-36265A381717}.Debug|x86.Build.0 = Debug|Any CPU - {F2E27E1C-2E47-42C1-9AC7-36265A381717}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F2E27E1C-2E47-42C1-9AC7-36265A381717}.Release|Any CPU.Build.0 = Release|Any CPU - {F2E27E1C-2E47-42C1-9AC7-36265A381717}.Release|x64.ActiveCfg = Release|Any CPU - {F2E27E1C-2E47-42C1-9AC7-36265A381717}.Release|x64.Build.0 = Release|Any CPU - {F2E27E1C-2E47-42C1-9AC7-36265A381717}.Release|x86.ActiveCfg = Release|Any CPU - {F2E27E1C-2E47-42C1-9AC7-36265A381717}.Release|x86.Build.0 = Release|Any CPU - {CA9948CA-B3FA-4C2E-A726-5E47BAD19457}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CA9948CA-B3FA-4C2E-A726-5E47BAD19457}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CA9948CA-B3FA-4C2E-A726-5E47BAD19457}.Debug|x64.ActiveCfg = Debug|Any CPU - {CA9948CA-B3FA-4C2E-A726-5E47BAD19457}.Debug|x64.Build.0 = Debug|Any CPU - {CA9948CA-B3FA-4C2E-A726-5E47BAD19457}.Debug|x86.ActiveCfg = Debug|Any CPU - {CA9948CA-B3FA-4C2E-A726-5E47BAD19457}.Debug|x86.Build.0 = Debug|Any CPU - {CA9948CA-B3FA-4C2E-A726-5E47BAD19457}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CA9948CA-B3FA-4C2E-A726-5E47BAD19457}.Release|Any CPU.Build.0 = Release|Any CPU - {CA9948CA-B3FA-4C2E-A726-5E47BAD19457}.Release|x64.ActiveCfg = Release|Any CPU - {CA9948CA-B3FA-4C2E-A726-5E47BAD19457}.Release|x64.Build.0 = Release|Any CPU - {CA9948CA-B3FA-4C2E-A726-5E47BAD19457}.Release|x86.ActiveCfg = Release|Any CPU - {CA9948CA-B3FA-4C2E-A726-5E47BAD19457}.Release|x86.Build.0 = Release|Any CPU - {97EA0A7D-FE5E-47D1-ADDC-4BFD702F55AB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {97EA0A7D-FE5E-47D1-ADDC-4BFD702F55AB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {97EA0A7D-FE5E-47D1-ADDC-4BFD702F55AB}.Debug|x64.ActiveCfg = Debug|Any CPU - {97EA0A7D-FE5E-47D1-ADDC-4BFD702F55AB}.Debug|x64.Build.0 = Debug|Any CPU - {97EA0A7D-FE5E-47D1-ADDC-4BFD702F55AB}.Debug|x86.ActiveCfg = Debug|Any CPU - {97EA0A7D-FE5E-47D1-ADDC-4BFD702F55AB}.Debug|x86.Build.0 = Debug|Any CPU - {97EA0A7D-FE5E-47D1-ADDC-4BFD702F55AB}.Release|Any CPU.ActiveCfg = Release|Any CPU - {97EA0A7D-FE5E-47D1-ADDC-4BFD702F55AB}.Release|Any CPU.Build.0 = Release|Any CPU - {97EA0A7D-FE5E-47D1-ADDC-4BFD702F55AB}.Release|x64.ActiveCfg = Release|Any CPU - {97EA0A7D-FE5E-47D1-ADDC-4BFD702F55AB}.Release|x64.Build.0 = Release|Any CPU - {97EA0A7D-FE5E-47D1-ADDC-4BFD702F55AB}.Release|x86.ActiveCfg = Release|Any CPU - {97EA0A7D-FE5E-47D1-ADDC-4BFD702F55AB}.Release|x86.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {ECE91401-329E-4615-8684-8E910D2741C4} = {E059A46B-56E3-41E2-83F4-B5D180056F3B} - {F000C49D-3857-42A4-918D-DA4C08691FE2} = {E059A46B-56E3-41E2-83F4-B5D180056F3B} - {641922CD-E6F5-41E7-A085-EE07C2A7328D} = {7260DED9-22A9-4E9D-92F4-5E8A4404DEAF} - {958AD6D2-174B-4B5B-BEFC-FA64B5159334} = {7260DED9-22A9-4E9D-92F4-5E8A4404DEAF} - {E8AD67A4-77D3-4B85-AE19-4711388B62B1} = {7260DED9-22A9-4E9D-92F4-5E8A4404DEAF} - {E38FDBB0-08C1-444E-A449-69C8A59D721B} = {7260DED9-22A9-4E9D-92F4-5E8A4404DEAF} - {A6C8050D-7C18-4585-ADCF-833AC1765847} = {7260DED9-22A9-4E9D-92F4-5E8A4404DEAF} - {A4859630-F9F7-4F5C-9FF3-6C013D7C58FA} = {7260DED9-22A9-4E9D-92F4-5E8A4404DEAF} - {A7ABAC29-F73F-456D-AE54-46842CFC2E10} = {7260DED9-22A9-4E9D-92F4-5E8A4404DEAF} - {FD37F740-A654-4117-BFB6-9112CE4C1D3B} = {A7ABAC29-F73F-456D-AE54-46842CFC2E10} - {C1E2C117-BE47-4E29-94B3-753262D97A5C} = {A7ABAC29-F73F-456D-AE54-46842CFC2E10} - {F16C1A7C-A2BD-4EB1-8BC8-23B1375F3B9E} = {A7ABAC29-F73F-456D-AE54-46842CFC2E10} - {1C4BF2D3-44A8-4A71-B031-15B983663CB0} = {A7ABAC29-F73F-456D-AE54-46842CFC2E10} - {C0FFB29E-4696-4875-9039-E5FA1AC5A42A} = {A7ABAC29-F73F-456D-AE54-46842CFC2E10} - {3B1A56F8-B3E0-4F33-A717-50BDD4FBE12E} = {A27FF193-195B-4474-8E6C-840B2E339373} - {35A8AE1D-ED82-485E-A8E6-A357B3CB31B3} = {3D9B9B2C-E379-41BD-83D4-2E099FBDA107} - {8D49A92D-B4AA-4A5C-99C1-B4DCBD5491DD} = {3D9B9B2C-E379-41BD-83D4-2E099FBDA107} - {C987E45D-53AE-49EB-BD22-A15789B12F7F} = {3D9B9B2C-E379-41BD-83D4-2E099FBDA107} - {8D09F716-F010-4332-AB98-22246C0FE8AA} = {3A423375-4610-4366-B9D5-C2B29A53C50D} - {FE32E389-1868-4AA2-9E47-0FC823C25106} = {3A423375-4610-4366-B9D5-C2B29A53C50D} - {B998B96D-E3CD-440E-9BFD-8F4EDC9D6732} = {E9E9CF3C-CE9B-4282-B2BB-97EFC3872798} - {44E0D4F3-4430-4175-B482-0D1AEE4BB699} = {E9E9CF3C-CE9B-4282-B2BB-97EFC3872798} - {4C5AB32A-3C7E-4A55-96A7-1F5248CFE929} = {44E0D4F3-4430-4175-B482-0D1AEE4BB699} - {423CCF23-C0B4-4D21-896C-16DC98689DB5} = {44E0D4F3-4430-4175-B482-0D1AEE4BB699} - {D6AEB328-EBC0-40B1-8936-301597883DFA} = {44E0D4F3-4430-4175-B482-0D1AEE4BB699} - {6BA2DCAA-CB68-4AE2-BBBE-746A728D30E0} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {766CB6A1-0507-4367-A6CC-9C2EC6A39732} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {992288A5-6E70-4F2D-99A6-03439BF7A5E3} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {27A226BA-C94A-4E99-897D-EDFB856CCCB5} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {443DBEC1-9620-4287-A8E7-DFE46A227BE6} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {C3A07F30-F2EA-4A9C-8A83-8C0BC8144863} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {3A25A675-8867-420A-8921-4B6D617EBE2F} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {B25439E1-C944-4FE1-8678-AC9E866AC4EA} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {214B9F12-BF3F-430F-85BC-98C6CFFFE5F8} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {574F245D-ED2E-4B5F-9929-8E8377412E6D} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {7BE4D31D-D31F-422E-8C54-39B91A9A4DE4} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {8EF63B6F-A1D9-469B-9A50-DE1613ED47A5} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {A9291B4E-7049-4574-AC45-8D642AD3D9B0} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {6B847B89-DEFB-478C-B0D8-0F309602A0C5} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {3D316CA9-55C6-4D72-A408-382935555361} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {E0EDCB3C-C93B-4368-9289-035D7D35382B} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {3C001B2F-2A04-478C-8A7A-1D121E8A4BB1} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {FF3A5823-43F0-4C98-87C4-3C5973F3C7D7} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {AB47EF50-D7F4-47AB-A49D-FFB8874EC9F7} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {8C18A50B-EAEE-4CE0-8FFC-0957FD6B5DFD} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {6F46EE1F-5A3A-4D16-94C4-6CF7147BC75B} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {EF6E0BF5-F018-4C76-A7E8-EF52D2C7D9C1} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {697B279A-8BC0-49C2-A57F-667E9AD81E9A} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {F94690E9-258C-4C10-AC26-FA31F6EB9D35} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {A2AB7E2D-0FE2-4740-95E7-CE600CBD4F44} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {71209D14-8469-40FB-B052-8308AF22A0EC} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {86CBF0C9-76C8-4084-9758-E36731AEC1D7} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {EA169B0E-3F8C-4436-82F4-56768263D256} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {1CDF7EC6-A25A-44BC-8CD3-C9F6AD13CF0B} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {5AEEAA34-01A0-418D-A8D0-E89A5B9A0EF1} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {BBDB70EB-2C08-43E7-8D82-BEE18C8881C8} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {AB827016-9D0A-4443-BFF0-80CB9E947D39} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {707BB7F9-3E71-4364-8AD0-949735B5D33C} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {E09006B7-2022-43CD-A0D9-127282F95A57} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {61E8C8E2-1CF4-42DA-8822-AFEC7FA47F16} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {1F501D4D-CEA4-445B-86C9-7215A6811368} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {B5037DC9-2690-42FA-8725-514E4A9EFEAD} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {AC7782F2-1F03-4615-A600-A7FE0FDEC5E5} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {D5C02B69-4E7B-4628-8BDA-B622A2FB2A97} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {74F10D31-161F-49A4-ACD7-282211447CE4} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {DBA8E5FE-DE74-4E24-A9A2-0FBBCC1C2792} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {2BBA2091-C991-4696-B70F-5C2D114D5674} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {D9E125B3-8FFD-47CE-9C0E-FF5CEAF633AE} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {DA1687B8-10E4-4F50-B074-60D20912A9BD} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {97CE175F-9290-479F-A6EB-EEF4C6816624} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {492ADBEC-D788-4039-A544-E1510D9328C1} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {B0A51484-8A24-4B9C-996B-415EB7733D56} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {D809A2F0-0B7B-4B5D-B70C-05EFD3203301} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {365365A2-18A9-4EF8-A4CB-F096DAF078D9} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {92D23FF6-3C79-46CD-98ED-24DA16F8FDC3} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {D8C72607-7E3E-4124-A065-A57F23E9F2BA} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {4272499A-C424-41DF-B6B8-DF3C19416BE2} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {E01CD19E-B0BE-4480-8B8E-3701DE862E62} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {AA87CAA1-2456-4108-A02F-E16B9B8A98EE} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {DC2F67CC-79DD-4F7C-AFD1-AC0D12B331C9} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {56DA124E-A37A-44DE-9DED-2764DDF0816C} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {527DB7FD-B118-4E49-B68A-55AAE9BFA109} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {BB6E57A6-5434-46D4-AA09-72DC29794506} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {557608E1-1DF3-4A24-80EB-C557C676A9CE} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {9241EDB4-8FCE-4F8E-9727-C9557C59907C} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {3FAF725B-A628-4531-9F61-499660CD4347} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {04262990-929C-42BF-85A9-21C25FA95617} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {DC47C40A-FC38-44E4-94A4-ADE794E76309} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {ED210157-461B-45BB-9D86-B81A62792C30} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {DA137BD4-F7F1-4D53-855F-5EC40CEA36B0} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {0CDAB70B-71DC-43BE-ACB7-AD2EE3541FFB} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {F88118E1-6F4A-4F89-B047-5FFD2889B9F0} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {74D21785-2FAB-4266-B7C4-E311EC8EE0DF} = {7260DED9-22A9-4E9D-92F4-5E8A4404DEAF} - {E4C01A3F-D3C1-4639-A6A9-930E918843DD} = {7260DED9-22A9-4E9D-92F4-5E8A4404DEAF} - {DE297C91-B3E9-4C6F-B74D-0AF9EFEBF684} = {A27FF193-195B-4474-8E6C-840B2E339373} - {956F540A-3CDA-4913-9373-1A4E8A93BDD8} = {08791FEE-761D-40EF-B701-1D31FD1E6E53} - {B13CDE69-ED22-4664-AAD7-686ED8CD5E88} = {08791FEE-761D-40EF-B701-1D31FD1E6E53} - {A5C132FB-1E03-4DA9-8D05-80755ED1D0ED} = {B0EEB429-4C8C-42AA-8822-3058E7DBC98F} - {173D84A3-0F37-480F-AC0F-7E2DBBE32B28} = {B0EEB429-4C8C-42AA-8822-3058E7DBC98F} - {4664276D-606A-4BB3-873A-9EE84FB22877} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {BBF37AF9-8290-4B70-8BA8-0F6017B3B620} = {46E4300C-5726-4108-B9A2-18BB94EB26ED} - {CD0EF85C-4187-4515-A355-E5A0D4485F40} = {BDE2397D-C53A-4783-8B3A-1F54F48A6926} - {F31E8118-014E-4CCE-8A48-5282F7B9BB3E} = {BDE2397D-C53A-4783-8B3A-1F54F48A6926} - {B70F90C7-2696-4050-B24E-BF0308F4E059} = {7260DED9-22A9-4E9D-92F4-5E8A4404DEAF} - {A5617A9D-C71E-44DE-936C-27611EB40A02} = {7260DED9-22A9-4E9D-92F4-5E8A4404DEAF} - {21BB9C13-20C1-4F2B-80E4-D7C64AA3BD05} = {7260DED9-22A9-4E9D-92F4-5E8A4404DEAF} - {D141CFEE-D10A-406B-8963-F86FA13732E3} = {21BB9C13-20C1-4F2B-80E4-D7C64AA3BD05} - {F2E27E1C-2E47-42C1-9AC7-36265A381717} = {44E0D4F3-4430-4175-B482-0D1AEE4BB699} - {F65EFF0F-ACF3-46BD-9A8F-CDA94AF1885A} = {CCC82E97-7B58-43E2-BBBD-23D82F926367} - {CA9948CA-B3FA-4C2E-A726-5E47BAD19457} = {F65EFF0F-ACF3-46BD-9A8F-CDA94AF1885A} - {97EA0A7D-FE5E-47D1-ADDC-4BFD702F55AB} = {F65EFF0F-ACF3-46BD-9A8F-CDA94AF1885A} - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {CC3C47E1-AD1A-4619-9CD3-E08A0148E5CE} - EndGlobalSection -EndGlobal diff --git a/src/Components/Components/perf/AssemblyInfo.cs b/src/Components/Components/perf/AssemblyInfo.cs deleted file mode 100644 index 59c4ce5180..0000000000 --- a/src/Components/Components/perf/AssemblyInfo.cs +++ /dev/null @@ -1,4 +0,0 @@ -// 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. - -[assembly: BenchmarkDotNet.Attributes.AspNetCoreBenchmark] \ No newline at end of file diff --git a/src/Components/Components/perf/Microsoft.AspNetCore.Components.Performance.csproj b/src/Components/Components/perf/Microsoft.AspNetCore.Components.Performance.csproj deleted file mode 100644 index a893d64abd..0000000000 --- a/src/Components/Components/perf/Microsoft.AspNetCore.Components.Performance.csproj +++ /dev/null @@ -1,16 +0,0 @@ - - - - $(DefaultNetCoreTargetFramework) - Exe - true - true - - - - - - - - - diff --git a/src/Components/Components/perf/Program.cs b/src/Components/Components/perf/Program.cs deleted file mode 100644 index 8602bc9462..0000000000 --- a/src/Components/Components/perf/Program.cs +++ /dev/null @@ -1,47 +0,0 @@ -// 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.Diagnostics; -using Microsoft.AspNetCore.Components.Performance; - -namespace Microsoft.AspNetCore.BenchmarkDotNet.Runner -{ - internal partial class Program - { - static partial void BeforeMain(string[] args) - { - if (args.Length == 0 || args[0] != "--profile") - { - return; - } - - // Write code here if you want to profile something. Normally Benchmark.NET launches - // a separate process, which can be hard to profile. - // - // See: https://github.com/dotnet/BenchmarkDotNet/issues/387 - - // Example: - //Console.WriteLine("Starting..."); - //var stopwatch = Stopwatch.StartNew(); - //var benchmark = new RenderTreeDiffBuilderBenchmark(); - - //for (var i = 0; i < 100000; i++) - //{ - // benchmark.ComputeDiff_SingleFormField(); - // benchmark.ComputeDiff_SingleFormField(); - // benchmark.ComputeDiff_SingleFormField(); - // benchmark.ComputeDiff_SingleFormField(); - // benchmark.ComputeDiff_SingleFormField(); - // benchmark.ComputeDiff_SingleFormField(); - // benchmark.ComputeDiff_SingleFormField(); - // benchmark.ComputeDiff_SingleFormField(); - // benchmark.ComputeDiff_SingleFormField(); - // benchmark.ComputeDiff_SingleFormField(); - //} - - //Console.WriteLine($"Done after {stopwatch.ElapsedMilliseconds}ms"); - //Environment.Exit(0); - } - } -} diff --git a/src/Components/Components/perf/RenderTreeDiffBuilderBenchmark.cs b/src/Components/Components/perf/RenderTreeDiffBuilderBenchmark.cs deleted file mode 100644 index 51d7fea9fc..0000000000 --- a/src/Components/Components/perf/RenderTreeDiffBuilderBenchmark.cs +++ /dev/null @@ -1,114 +0,0 @@ -// 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 BenchmarkDotNet.Attributes; -using Microsoft.AspNetCore.Components.Rendering; -using Microsoft.AspNetCore.Components.RenderTree; -using Microsoft.Extensions.Logging.Abstractions; - -namespace Microsoft.AspNetCore.Components.Performance -{ - public class RenderTreeDiffBuilderBenchmark - { - private readonly Renderer renderer; - private readonly RenderTreeBuilder original; - private readonly RenderTreeBuilder modified; - private readonly RenderBatchBuilder builder; - - public RenderTreeDiffBuilderBenchmark() - { - builder = new RenderBatchBuilder(); - renderer = new FakeRenderer(); - - // A simple component for basic tests -- this is similar to what MVC scaffolding generates - // for bootstrap3 form fields, but modified to be more Component-like. - original = new RenderTreeBuilder(); - original.OpenElement(0, "div"); - original.AddAttribute(1, "class", "form-group"); - - original.OpenElement(2, "label"); - original.AddAttribute(3, "class", "control-label"); - original.AddAttribute(4, "for", "name"); - original.AddAttribute(5, "data-unvalidated", true); - original.AddContent(6, "Car"); - original.CloseElement(); - - original.OpenElement(7, "input"); - original.AddAttribute(8, "class", "form-control"); - original.AddAttribute(9, "type", "text"); - original.AddAttribute(10, "name", "name"); // Notice the gap in sequence numbers - original.AddAttribute(12, "value", ""); - original.CloseElement(); - - original.OpenElement(13, "span"); - original.AddAttribute(14, "class", "text-danger field-validation-valid"); - original.AddContent(15, ""); - original.CloseElement(); - - original.CloseElement(); - - // Now simulate some input - modified = new RenderTreeBuilder(); - modified.OpenElement(0, "div"); - modified.AddAttribute(1, "class", "form-group"); - - modified.OpenElement(2, "label"); - modified.AddAttribute(3, "class", "control-label"); - modified.AddAttribute(4, "for", "name"); - modified.AddAttribute(5, "data-unvalidated", false); - modified.AddContent(6, "Car"); - modified.CloseElement(); - - modified.OpenElement(7, "input"); - modified.AddAttribute(8, "class", "form-control"); - modified.AddAttribute(9, "type", "text"); - modified.AddAttribute(10, "name", "name"); - modified.AddAttribute(11, "data-validation-state", "invalid"); - modified.AddAttribute(12, "value", "Lamborghini"); - modified.CloseElement(); - - modified.OpenElement(13, "span"); - modified.AddAttribute(14, "class", "text-danger field-validation-invalid"); // changed - modified.AddContent(15, "No, you can't afford that."); - modified.CloseElement(); - - modified.CloseElement(); - } - - [Benchmark(Description = "RenderTreeDiffBuilder: Input and validation on a single form field.", Baseline = true)] - public void ComputeDiff_SingleFormField() - { - builder.ClearStateForCurrentBatch(); - var diff = RenderTreeDiffBuilder.ComputeDiff(renderer, builder, 0, original.GetFrames(), modified.GetFrames()); - GC.KeepAlive(diff); - } - - private class FakeRenderer : Renderer - { - public FakeRenderer() - : base(new TestServiceProvider(), NullLoggerFactory.Instance) - { - } - - public override Dispatcher Dispatcher { get; } = Dispatcher.CreateDefault(); - - protected override void HandleException(Exception exception) - { - throw new NotImplementedException(); - } - - protected override Task UpdateDisplayAsync(in RenderBatch renderBatch) - => Task.CompletedTask; - } - - private class TestServiceProvider : IServiceProvider - { - public object GetService(Type serviceType) - { - return null; - } - } - } -} diff --git a/src/Components/Components/perf/readme.md b/src/Components/Components/perf/readme.md deleted file mode 100644 index 82e7adfab7..0000000000 --- a/src/Components/Components/perf/readme.md +++ /dev/null @@ -1,35 +0,0 @@ -# Benchmarks - -## Instructions - -### Run All Benchmarks - -To run all use `*` as parameter -``` -dotnet run -c Release -- * -``` - -### Interactive Mode - -To see the list of benchmarks run (and choose interactively): -``` -dotnet run -c Release -``` - -### Run Specific Benchmark - -To run a specific benchmark add it as parameter -``` -dotnet run -c Release -- -``` - - -## Troubleshooting - -The runner will create logs in the `\BenchmarkDotNet.Artifacts` directory. That should include a lot more information -than what gets printed to the console. - -## Results - -Also in the `\BenchmarkDotNet.Artifacts\results` directive you'll find some markdown-formatted tables suitable for posting -in a github comment. \ No newline at end of file diff --git a/src/Components/Components/ref/Directory.Build.props b/src/Components/Components/ref/Directory.Build.props deleted file mode 100644 index 322f33d633..0000000000 --- a/src/Components/Components/ref/Directory.Build.props +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/src/Components/Components/ref/Microsoft.AspNetCore.Components.csproj b/src/Components/Components/ref/Microsoft.AspNetCore.Components.csproj deleted file mode 100644 index 8a32a89b9e..0000000000 --- a/src/Components/Components/ref/Microsoft.AspNetCore.Components.csproj +++ /dev/null @@ -1,19 +0,0 @@ - - - - netstandard2.0;$(DefaultNetCoreTargetFramework) - - - - - - - - - - - - - - - diff --git a/src/Components/Components/ref/Microsoft.AspNetCore.Components.netcoreapp.cs b/src/Components/Components/ref/Microsoft.AspNetCore.Components.netcoreapp.cs deleted file mode 100644 index c4a48435b4..0000000000 --- a/src/Components/Components/ref/Microsoft.AspNetCore.Components.netcoreapp.cs +++ /dev/null @@ -1,550 +0,0 @@ -// 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. - -namespace Microsoft.AspNetCore.Components -{ - public static partial class BindConverter - { - public static bool FormatValue(bool value, System.Globalization.CultureInfo culture = null) { throw null; } - public static string FormatValue(System.DateTime value, System.Globalization.CultureInfo culture = null) { throw null; } - public static string FormatValue(System.DateTime value, string format, System.Globalization.CultureInfo culture = null) { throw null; } - public static string FormatValue(System.DateTimeOffset value, System.Globalization.CultureInfo culture = null) { throw null; } - public static string FormatValue(System.DateTimeOffset value, string format, System.Globalization.CultureInfo culture = null) { throw null; } - public static string FormatValue(decimal value, System.Globalization.CultureInfo culture = null) { throw null; } - public static string FormatValue(double value, System.Globalization.CultureInfo culture = null) { throw null; } - public static string FormatValue(int value, System.Globalization.CultureInfo culture = null) { throw null; } - public static string FormatValue(long value, System.Globalization.CultureInfo culture = null) { throw null; } - public static bool? FormatValue(bool? value, System.Globalization.CultureInfo culture = null) { throw null; } - public static string FormatValue(System.DateTimeOffset? value, System.Globalization.CultureInfo culture = null) { throw null; } - public static string FormatValue(System.DateTimeOffset? value, string format, System.Globalization.CultureInfo culture = null) { throw null; } - public static string FormatValue(System.DateTime? value, System.Globalization.CultureInfo culture = null) { throw null; } - public static string FormatValue(System.DateTime? value, string format, System.Globalization.CultureInfo culture = null) { throw null; } - public static string FormatValue(decimal? value, System.Globalization.CultureInfo culture = null) { throw null; } - public static string FormatValue(double? value, System.Globalization.CultureInfo culture = null) { throw null; } - public static string FormatValue(int? value, System.Globalization.CultureInfo culture = null) { throw null; } - public static string FormatValue(long? value, System.Globalization.CultureInfo culture = null) { throw null; } - public static string FormatValue(float? value, System.Globalization.CultureInfo culture = null) { throw null; } - public static string FormatValue(float value, System.Globalization.CultureInfo culture = null) { throw null; } - public static string FormatValue(string value, System.Globalization.CultureInfo culture = null) { throw null; } - public static object FormatValue(T value, System.Globalization.CultureInfo culture = null) { throw null; } - public static bool TryConvertToBool(object obj, System.Globalization.CultureInfo culture, out bool value) { throw null; } - public static bool TryConvertToDateTime(object obj, System.Globalization.CultureInfo culture, out System.DateTime value) { throw null; } - public static bool TryConvertToDateTime(object obj, System.Globalization.CultureInfo culture, string format, out System.DateTime value) { throw null; } - public static bool TryConvertToDateTimeOffset(object obj, System.Globalization.CultureInfo culture, out System.DateTimeOffset value) { throw null; } - public static bool TryConvertToDateTimeOffset(object obj, System.Globalization.CultureInfo culture, string format, out System.DateTimeOffset value) { throw null; } - public static bool TryConvertToDecimal(object obj, System.Globalization.CultureInfo culture, out decimal value) { throw null; } - public static bool TryConvertToDouble(object obj, System.Globalization.CultureInfo culture, out double value) { throw null; } - public static bool TryConvertToFloat(object obj, System.Globalization.CultureInfo culture, out float value) { throw null; } - public static bool TryConvertToInt(object obj, System.Globalization.CultureInfo culture, out int value) { throw null; } - public static bool TryConvertToLong(object obj, System.Globalization.CultureInfo culture, out long value) { throw null; } - public static bool TryConvertToNullableBool(object obj, System.Globalization.CultureInfo culture, out bool? value) { throw null; } - public static bool TryConvertToNullableDateTime(object obj, System.Globalization.CultureInfo culture, out System.DateTime? value) { throw null; } - public static bool TryConvertToNullableDateTime(object obj, System.Globalization.CultureInfo culture, string format, out System.DateTime? value) { throw null; } - public static bool TryConvertToNullableDateTimeOffset(object obj, System.Globalization.CultureInfo culture, out System.DateTimeOffset? value) { throw null; } - public static bool TryConvertToNullableDateTimeOffset(object obj, System.Globalization.CultureInfo culture, string format, out System.DateTimeOffset? value) { throw null; } - public static bool TryConvertToNullableDecimal(object obj, System.Globalization.CultureInfo culture, out decimal? value) { throw null; } - public static bool TryConvertToNullableDouble(object obj, System.Globalization.CultureInfo culture, out double? value) { throw null; } - public static bool TryConvertToNullableFloat(object obj, System.Globalization.CultureInfo culture, out float? value) { throw null; } - public static bool TryConvertToNullableInt(object obj, System.Globalization.CultureInfo culture, out int? value) { throw null; } - public static bool TryConvertToNullableLong(object obj, System.Globalization.CultureInfo culture, out long? value) { throw null; } - public static bool TryConvertToString(object obj, System.Globalization.CultureInfo culture, out string value) { throw null; } - public static bool TryConvertTo(object obj, System.Globalization.CultureInfo culture, out T value) { throw null; } - } - [System.AttributeUsageAttribute(System.AttributeTargets.Class, AllowMultiple=true, Inherited=true)] - public sealed partial class BindElementAttribute : System.Attribute - { - public BindElementAttribute(string element, string suffix, string valueAttribute, string changeAttribute) { } - public string ChangeAttribute { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - public string Element { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - public string Suffix { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - public string ValueAttribute { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - } - [System.AttributeUsageAttribute(System.AttributeTargets.Property, AllowMultiple=false, Inherited=true)] - public sealed partial class CascadingParameterAttribute : System.Attribute - { - public CascadingParameterAttribute() { } - public string Name { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } - } - public partial class CascadingValue : Microsoft.AspNetCore.Components.IComponent - { - public CascadingValue() { } - [Microsoft.AspNetCore.Components.ParameterAttribute] - public Microsoft.AspNetCore.Components.RenderFragment ChildContent { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } - [Microsoft.AspNetCore.Components.ParameterAttribute] - public bool IsFixed { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } - [Microsoft.AspNetCore.Components.ParameterAttribute] - public string Name { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } - [Microsoft.AspNetCore.Components.ParameterAttribute] - public TValue Value { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } - public void Attach(Microsoft.AspNetCore.Components.RenderHandle renderHandle) { } - public System.Threading.Tasks.Task SetParametersAsync(Microsoft.AspNetCore.Components.ParameterView parameters) { throw null; } - } - public partial class ChangeEventArgs : System.EventArgs - { - public ChangeEventArgs() { } - public object Value { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } - } - public abstract partial class ComponentBase : Microsoft.AspNetCore.Components.IComponent, Microsoft.AspNetCore.Components.IHandleAfterRender, Microsoft.AspNetCore.Components.IHandleEvent - { - public ComponentBase() { } - protected virtual void BuildRenderTree(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder builder) { } - protected System.Threading.Tasks.Task InvokeAsync(System.Action workItem) { throw null; } - protected System.Threading.Tasks.Task InvokeAsync(System.Func workItem) { throw null; } - void Microsoft.AspNetCore.Components.IComponent.Attach(Microsoft.AspNetCore.Components.RenderHandle renderHandle) { } - System.Threading.Tasks.Task Microsoft.AspNetCore.Components.IHandleAfterRender.OnAfterRenderAsync() { throw null; } - System.Threading.Tasks.Task Microsoft.AspNetCore.Components.IHandleEvent.HandleEventAsync(Microsoft.AspNetCore.Components.EventCallbackWorkItem callback, object arg) { throw null; } - protected virtual void OnAfterRender(bool firstRender) { } - protected virtual System.Threading.Tasks.Task OnAfterRenderAsync(bool firstRender) { throw null; } - protected virtual void OnInitialized() { } - protected virtual System.Threading.Tasks.Task OnInitializedAsync() { throw null; } - protected virtual void OnParametersSet() { } - protected virtual System.Threading.Tasks.Task OnParametersSetAsync() { throw null; } - public virtual System.Threading.Tasks.Task SetParametersAsync(Microsoft.AspNetCore.Components.ParameterView parameters) { throw null; } - protected virtual bool ShouldRender() { throw null; } - protected void StateHasChanged() { } - } - public abstract partial class Dispatcher - { - protected Dispatcher() { } - public void AssertAccess() { } - 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 workItem); - public abstract System.Threading.Tasks.Task InvokeAsync(System.Func> workItem); - public abstract System.Threading.Tasks.Task InvokeAsync(System.Func workItem); - protected void OnUnhandledException(System.UnhandledExceptionEventArgs e) { } - } - [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] - public readonly partial struct ElementReference - { - private readonly object _dummy; - public ElementReference(string id) { throw null; } - public string Id { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - } - [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] - public readonly partial struct EventCallback - { - private readonly object _dummy; - public static readonly Microsoft.AspNetCore.Components.EventCallback Empty; - public static readonly Microsoft.AspNetCore.Components.EventCallbackFactory Factory; - public EventCallback(Microsoft.AspNetCore.Components.IHandleEvent receiver, System.MulticastDelegate @delegate) { throw null; } - public bool HasDelegate { get { throw null; } } - public System.Threading.Tasks.Task InvokeAsync(object arg) { throw null; } - } - public sealed partial class EventCallbackFactory - { - public EventCallbackFactory() { } - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public Microsoft.AspNetCore.Components.EventCallback Create(object receiver, Microsoft.AspNetCore.Components.EventCallback callback) { throw null; } - public Microsoft.AspNetCore.Components.EventCallback Create(object receiver, System.Action callback) { throw null; } - public Microsoft.AspNetCore.Components.EventCallback Create(object receiver, System.Action callback) { throw null; } - public Microsoft.AspNetCore.Components.EventCallback Create(object receiver, System.Func callback) { throw null; } - public Microsoft.AspNetCore.Components.EventCallback Create(object receiver, System.Func callback) { throw null; } - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public Microsoft.AspNetCore.Components.EventCallback CreateInferred(object receiver, System.Action callback, TValue value) { throw null; } - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public Microsoft.AspNetCore.Components.EventCallback CreateInferred(object receiver, System.Func callback, TValue value) { throw null; } - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public Microsoft.AspNetCore.Components.EventCallback Create(object receiver, Microsoft.AspNetCore.Components.EventCallback callback) { throw null; } - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public Microsoft.AspNetCore.Components.EventCallback Create(object receiver, Microsoft.AspNetCore.Components.EventCallback callback) { throw null; } - public Microsoft.AspNetCore.Components.EventCallback Create(object receiver, System.Action callback) { throw null; } - public Microsoft.AspNetCore.Components.EventCallback Create(object receiver, System.Action callback) { throw null; } - public Microsoft.AspNetCore.Components.EventCallback Create(object receiver, System.Func callback) { throw null; } - public Microsoft.AspNetCore.Components.EventCallback Create(object receiver, System.Func callback) { throw null; } - } - public static partial class EventCallbackFactoryBinderExtensions - { - public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, bool existingValue, System.Globalization.CultureInfo culture = null) { throw null; } - public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, System.DateTimeOffset existingValue, System.Globalization.CultureInfo culture = null) { throw null; } - public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, System.DateTimeOffset existingValue, string format, System.Globalization.CultureInfo culture = null) { throw null; } - public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, System.DateTime existingValue, System.Globalization.CultureInfo culture = null) { throw null; } - public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, System.DateTime existingValue, string format, System.Globalization.CultureInfo culture = null) { throw null; } - public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, decimal existingValue, System.Globalization.CultureInfo culture = null) { throw null; } - public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, double existingValue, System.Globalization.CultureInfo culture = null) { throw null; } - public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, int existingValue, System.Globalization.CultureInfo culture = null) { throw null; } - public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, long existingValue, System.Globalization.CultureInfo culture = null) { throw null; } - public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, bool? existingValue, System.Globalization.CultureInfo culture = null) { throw null; } - public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, System.DateTimeOffset? existingValue, System.Globalization.CultureInfo culture = null) { throw null; } - public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, System.DateTimeOffset? existingValue, string format, System.Globalization.CultureInfo culture = null) { throw null; } - public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, System.DateTime? existingValue, System.Globalization.CultureInfo culture = null) { throw null; } - public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, System.DateTime? existingValue, string format, System.Globalization.CultureInfo culture = null) { throw null; } - public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, decimal? existingValue, System.Globalization.CultureInfo culture = null) { throw null; } - public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, double? existingValue, System.Globalization.CultureInfo culture = null) { throw null; } - public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, int? existingValue, System.Globalization.CultureInfo culture = null) { throw null; } - public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, long? existingValue, System.Globalization.CultureInfo culture = null) { throw null; } - public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, float? existingValue, System.Globalization.CultureInfo culture = null) { throw null; } - public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, float existingValue, System.Globalization.CultureInfo culture = null) { throw null; } - public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, string existingValue, System.Globalization.CultureInfo culture = null) { throw null; } - public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, T existingValue, System.Globalization.CultureInfo culture = null) { throw null; } - } - public static partial class EventCallbackFactoryEventArgsExtensions - { - public static Microsoft.AspNetCore.Components.EventCallback Create(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action callback) { throw null; } - public static Microsoft.AspNetCore.Components.EventCallback Create(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action callback) { throw null; } - public static Microsoft.AspNetCore.Components.EventCallback Create(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Func callback) { throw null; } - public static Microsoft.AspNetCore.Components.EventCallback Create(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Func callback) { throw null; } - } - [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] - public readonly partial struct EventCallbackWorkItem - { - private readonly object _dummy; - public static readonly Microsoft.AspNetCore.Components.EventCallbackWorkItem Empty; - public EventCallbackWorkItem(System.MulticastDelegate @delegate) { throw null; } - public System.Threading.Tasks.Task InvokeAsync(object arg) { throw null; } - } - [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] - public readonly partial struct EventCallback - { - private readonly object _dummy; - public static readonly Microsoft.AspNetCore.Components.EventCallback Empty; - public EventCallback(Microsoft.AspNetCore.Components.IHandleEvent receiver, System.MulticastDelegate @delegate) { throw null; } - public bool HasDelegate { get { throw null; } } - public System.Threading.Tasks.Task InvokeAsync(TValue arg) { throw null; } - } - [System.AttributeUsageAttribute(System.AttributeTargets.Class, AllowMultiple=true, Inherited=true)] - public sealed partial class EventHandlerAttribute : System.Attribute - { - public EventHandlerAttribute(string attributeName, System.Type eventArgsType) { } - public EventHandlerAttribute(string attributeName, System.Type eventArgsType, bool enableStopPropagation, bool enablePreventDefault) { } - public string AttributeName { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - public bool EnablePreventDefault { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - public bool EnableStopPropagation { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - public System.Type EventArgsType { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - } - public partial interface IComponent - { - void Attach(Microsoft.AspNetCore.Components.RenderHandle renderHandle); - System.Threading.Tasks.Task SetParametersAsync(Microsoft.AspNetCore.Components.ParameterView parameters); - } - public partial interface IHandleAfterRender - { - System.Threading.Tasks.Task OnAfterRenderAsync(); - } - public partial interface IHandleEvent - { - System.Threading.Tasks.Task HandleEventAsync(Microsoft.AspNetCore.Components.EventCallbackWorkItem item, object arg); - } - [System.AttributeUsageAttribute(System.AttributeTargets.Property, AllowMultiple=false, Inherited=true)] - public sealed partial class InjectAttribute : System.Attribute - { - public InjectAttribute() { } - } - [System.AttributeUsageAttribute(System.AttributeTargets.Class, AllowMultiple=false, Inherited=true)] - public sealed partial class LayoutAttribute : System.Attribute - { - public LayoutAttribute(System.Type layoutType) { } - public System.Type LayoutType { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - } - public abstract partial class LayoutComponentBase : Microsoft.AspNetCore.Components.ComponentBase - { - protected LayoutComponentBase() { } - [Microsoft.AspNetCore.Components.ParameterAttribute] - public Microsoft.AspNetCore.Components.RenderFragment Body { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } - } - public partial class LayoutView : Microsoft.AspNetCore.Components.IComponent - { - public LayoutView() { } - [Microsoft.AspNetCore.Components.ParameterAttribute] - public Microsoft.AspNetCore.Components.RenderFragment ChildContent { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } - [Microsoft.AspNetCore.Components.ParameterAttribute] - public System.Type Layout { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } - public void Attach(Microsoft.AspNetCore.Components.RenderHandle renderHandle) { } - public System.Threading.Tasks.Task SetParametersAsync(Microsoft.AspNetCore.Components.ParameterView parameters) { throw null; } - } - public sealed partial class LocationChangeException : System.Exception - { - public LocationChangeException(string message, System.Exception innerException) { } - } - [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] - public readonly partial struct MarkupString - { - private readonly object _dummy; - public MarkupString(string value) { throw null; } - public string Value { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - public static explicit operator Microsoft.AspNetCore.Components.MarkupString (string value) { throw null; } - public override string ToString() { throw null; } - } - public partial class NavigationException : System.Exception - { - public NavigationException(string uri) { } - public string Location { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - } - public abstract partial class NavigationManager - { - protected NavigationManager() { } - public string BaseUri { get { throw null; } protected set { } } - public string Uri { get { throw null; } protected set { } } - public event System.EventHandler LocationChanged { add { } remove { } } - protected virtual void EnsureInitialized() { } - protected void Initialize(string baseUri, string uri) { } - public void NavigateTo(string uri, bool forceLoad = false) { } - protected abstract void NavigateToCore(string uri, bool forceLoad); - protected void NotifyLocationChanged(bool isInterceptedLink) { } - public System.Uri ToAbsoluteUri(string relativeUri) { throw null; } - public string ToBaseRelativePath(string uri) { throw null; } - } - public abstract partial class OwningComponentBase : Microsoft.AspNetCore.Components.ComponentBase, System.IDisposable - { - protected OwningComponentBase() { } - protected bool IsDisposed { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - protected System.IServiceProvider ScopedServices { get { throw null; } } - protected virtual void Dispose(bool disposing) { } - void System.IDisposable.Dispose() { } - } - public abstract partial class OwningComponentBase : Microsoft.AspNetCore.Components.OwningComponentBase, System.IDisposable - { - protected OwningComponentBase() { } - protected TService Service { get { throw null; } } - } - [System.AttributeUsageAttribute(System.AttributeTargets.Property, AllowMultiple=false, Inherited=true)] - public sealed partial class ParameterAttribute : System.Attribute - { - public ParameterAttribute() { } - public bool CaptureUnmatchedValues { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } - } - [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] - public readonly partial struct ParameterValue - { - private readonly object _dummy; - private readonly int _dummyPrimitive; - public bool Cascading { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - public string Name { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - public object Value { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - } - [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] - public readonly partial struct ParameterView - { - private readonly object _dummy; - private readonly int _dummyPrimitive; - public static Microsoft.AspNetCore.Components.ParameterView Empty { get { throw null; } } - public static Microsoft.AspNetCore.Components.ParameterView FromDictionary(System.Collections.Generic.IDictionary parameters) { throw null; } - public Microsoft.AspNetCore.Components.ParameterView.Enumerator GetEnumerator() { throw null; } - public TValue GetValueOrDefault(string parameterName) { throw null; } - public TValue GetValueOrDefault(string parameterName, TValue defaultValue) { throw null; } - public void SetParameterProperties(object target) { } - public System.Collections.Generic.IReadOnlyDictionary ToDictionary() { throw null; } - public bool TryGetValue(string parameterName, out TValue result) { throw null; } - [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] - public partial struct Enumerator - { - private object _dummy; - private int _dummyPrimitive; - public Microsoft.AspNetCore.Components.ParameterValue Current { get { throw null; } } - public bool MoveNext() { throw null; } - } - } - public delegate void RenderFragment(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder builder); - public delegate Microsoft.AspNetCore.Components.RenderFragment RenderFragment(TValue value); - [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] - public readonly partial struct RenderHandle - { - private readonly object _dummy; - private readonly int _dummyPrimitive; - public Microsoft.AspNetCore.Components.Dispatcher Dispatcher { get { throw null; } } - public bool IsInitialized { get { throw null; } } - public void Render(Microsoft.AspNetCore.Components.RenderFragment renderFragment) { } - } - [System.AttributeUsageAttribute(System.AttributeTargets.Class, AllowMultiple=true, Inherited=false)] - public sealed partial class RouteAttribute : System.Attribute - { - public RouteAttribute(string template) { } - public string Template { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - } - public sealed partial class RouteData - { - public RouteData(System.Type pageType, System.Collections.Generic.IReadOnlyDictionary routeValues) { } - public System.Type PageType { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - public System.Collections.Generic.IReadOnlyDictionary RouteValues { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - } - public partial class RouteView : Microsoft.AspNetCore.Components.IComponent - { - public RouteView() { } - [Microsoft.AspNetCore.Components.ParameterAttribute] - public System.Type DefaultLayout { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } - [Microsoft.AspNetCore.Components.ParameterAttribute] - public Microsoft.AspNetCore.Components.RouteData RouteData { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } - public void Attach(Microsoft.AspNetCore.Components.RenderHandle renderHandle) { } - protected virtual void Render(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder builder) { } - public System.Threading.Tasks.Task SetParametersAsync(Microsoft.AspNetCore.Components.ParameterView parameters) { throw null; } - } -} -namespace Microsoft.AspNetCore.Components.CompilerServices -{ - public static partial class RuntimeHelpers - { - public static Microsoft.AspNetCore.Components.EventCallback CreateInferredEventCallback(object receiver, System.Action callback, T value) { throw null; } - public static Microsoft.AspNetCore.Components.EventCallback CreateInferredEventCallback(object receiver, System.Func callback, T value) { throw null; } - public static T TypeCheck(T value) { throw null; } - } -} -namespace Microsoft.AspNetCore.Components.Rendering -{ - public sealed partial class RenderTreeBuilder : System.IDisposable - { - public RenderTreeBuilder() { } - public void AddAttribute(int sequence, in Microsoft.AspNetCore.Components.RenderTree.RenderTreeFrame frame) { } - public void AddAttribute(int sequence, string name, Microsoft.AspNetCore.Components.EventCallback value) { } - public void AddAttribute(int sequence, string name, bool value) { } - public void AddAttribute(int sequence, string name, System.MulticastDelegate value) { } - public void AddAttribute(int sequence, string name, object value) { } - public void AddAttribute(int sequence, string name, string value) { } - public void AddAttribute(int sequence, string name, Microsoft.AspNetCore.Components.EventCallback value) { } - public void AddComponentReferenceCapture(int sequence, System.Action componentReferenceCaptureAction) { } - public void AddContent(int sequence, Microsoft.AspNetCore.Components.MarkupString markupContent) { } - public void AddContent(int sequence, Microsoft.AspNetCore.Components.RenderFragment fragment) { } - public void AddContent(int sequence, object textContent) { } - public void AddContent(int sequence, string textContent) { } - public void AddContent(int sequence, Microsoft.AspNetCore.Components.RenderFragment fragment, TValue value) { } - public void AddElementReferenceCapture(int sequence, System.Action elementReferenceCaptureAction) { } - public void AddMarkupContent(int sequence, string markupContent) { } - public void AddMultipleAttributes(int sequence, System.Collections.Generic.IEnumerable> attributes) { } - public void Clear() { } - public void CloseComponent() { } - public void CloseElement() { } - public void CloseRegion() { } - public Microsoft.AspNetCore.Components.RenderTree.ArrayRange GetFrames() { throw null; } - public void OpenComponent(int sequence, System.Type componentType) { } - public void OpenComponent(int sequence) where TComponent : Microsoft.AspNetCore.Components.IComponent { } - public void OpenElement(int sequence, string elementName) { } - public void OpenRegion(int sequence) { } - public void SetKey(object value) { } - public void SetUpdatesAttributeName(string updatesAttributeName) { } - void System.IDisposable.Dispose() { } - } -} -namespace Microsoft.AspNetCore.Components.RenderTree -{ - [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] - public readonly partial struct ArrayBuilderSegment : System.Collections.Generic.IEnumerable, System.Collections.IEnumerable - { - private readonly object _dummy; - private readonly int _dummyPrimitive; - public T[] Array { get { throw null; } } - public int Count { get { throw null; } } - public T this[int index] { get { throw null; } } - public int Offset { get { throw null; } } - System.Collections.Generic.IEnumerator System.Collections.Generic.IEnumerable.GetEnumerator() { throw null; } - System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { throw null; } - } - [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] - public readonly partial struct ArrayRange - { - public readonly T[] Array; - public readonly int Count; - public ArrayRange(T[] array, int count) { throw null; } - public Microsoft.AspNetCore.Components.RenderTree.ArrayRange Clone() { throw null; } - } - public partial class EventFieldInfo - { - public EventFieldInfo() { } - public int ComponentId { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } - public object FieldValue { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } - } - [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] - public readonly partial struct RenderBatch - { - private readonly object _dummy; - public Microsoft.AspNetCore.Components.RenderTree.ArrayRange DisposedComponentIDs { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - public Microsoft.AspNetCore.Components.RenderTree.ArrayRange DisposedEventHandlerIDs { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - public Microsoft.AspNetCore.Components.RenderTree.ArrayRange ReferenceFrames { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - public Microsoft.AspNetCore.Components.RenderTree.ArrayRange UpdatedComponents { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - } - public abstract partial class Renderer : System.IDisposable - { - public Renderer(System.IServiceProvider serviceProvider, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) { } - public abstract Microsoft.AspNetCore.Components.Dispatcher Dispatcher { get; } - public event System.UnhandledExceptionEventHandler UnhandledSynchronizationException { add { } remove { } } - protected internal int AssignRootComponentId(Microsoft.AspNetCore.Components.IComponent component) { throw null; } - public virtual System.Threading.Tasks.Task DispatchEventAsync(ulong eventHandlerId, Microsoft.AspNetCore.Components.RenderTree.EventFieldInfo fieldInfo, System.EventArgs eventArgs) { throw null; } - public void Dispose() { } - protected virtual void Dispose(bool disposing) { } - protected Microsoft.AspNetCore.Components.RenderTree.ArrayRange GetCurrentRenderTreeFrames(int componentId) { throw null; } - protected abstract void HandleException(System.Exception exception); - protected Microsoft.AspNetCore.Components.IComponent InstantiateComponent(System.Type componentType) { throw null; } - protected virtual void ProcessPendingRender() { } - protected System.Threading.Tasks.Task RenderRootComponentAsync(int componentId) { throw null; } - [System.Diagnostics.DebuggerStepThroughAttribute] - protected System.Threading.Tasks.Task RenderRootComponentAsync(int componentId, Microsoft.AspNetCore.Components.ParameterView initialParameters) { throw null; } - protected abstract System.Threading.Tasks.Task UpdateDisplayAsync(in Microsoft.AspNetCore.Components.RenderTree.RenderBatch renderBatch); - } - [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] - public readonly partial struct RenderTreeDiff - { - public readonly int ComponentId; - public readonly Microsoft.AspNetCore.Components.RenderTree.ArrayBuilderSegment Edits; - } - [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Explicit)] - public readonly partial struct RenderTreeEdit - { - [System.Runtime.InteropServices.FieldOffsetAttribute(8)] - public readonly int MoveToSiblingIndex; - [System.Runtime.InteropServices.FieldOffsetAttribute(8)] - public readonly int ReferenceFrameIndex; - [System.Runtime.InteropServices.FieldOffsetAttribute(16)] - public readonly string RemovedAttributeName; - [System.Runtime.InteropServices.FieldOffsetAttribute(4)] - public readonly int SiblingIndex; - [System.Runtime.InteropServices.FieldOffsetAttribute(0)] - public readonly Microsoft.AspNetCore.Components.RenderTree.RenderTreeEditType Type; - } - public enum RenderTreeEditType - { - PrependFrame = 1, - RemoveFrame = 2, - SetAttribute = 3, - RemoveAttribute = 4, - UpdateText = 5, - StepIn = 6, - StepOut = 7, - UpdateMarkup = 8, - PermutationListEntry = 9, - PermutationListEnd = 10, - } - public enum RenderTreeFrameType : short - { - None = (short)0, - Element = (short)1, - Text = (short)2, - Attribute = (short)3, - Component = (short)4, - Region = (short)5, - ElementReferenceCapture = (short)6, - ComponentReferenceCapture = (short)7, - Markup = (short)8, - } -} -namespace Microsoft.AspNetCore.Components.Routing -{ - public partial interface IHostEnvironmentNavigationManager - { - void Initialize(string baseUri, string uri); - } - public partial interface INavigationInterception - { - System.Threading.Tasks.Task EnableNavigationInterceptionAsync(); - } - public partial class LocationChangedEventArgs : System.EventArgs - { - public LocationChangedEventArgs(string location, bool isNavigationIntercepted) { } - public bool IsNavigationIntercepted { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - public string Location { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - } - public partial class Router : Microsoft.AspNetCore.Components.IComponent, Microsoft.AspNetCore.Components.IHandleAfterRender, System.IDisposable - { - public Router() { } - [Microsoft.AspNetCore.Components.ParameterAttribute] - public System.Collections.Generic.IEnumerable AdditionalAssemblies { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } - [Microsoft.AspNetCore.Components.ParameterAttribute] - public System.Reflection.Assembly AppAssembly { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } - [Microsoft.AspNetCore.Components.ParameterAttribute] - public Microsoft.AspNetCore.Components.RenderFragment Found { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } - [Microsoft.AspNetCore.Components.ParameterAttribute] - public Microsoft.AspNetCore.Components.RenderFragment NotFound { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } - public void Attach(Microsoft.AspNetCore.Components.RenderHandle renderHandle) { } - public void Dispose() { } - System.Threading.Tasks.Task Microsoft.AspNetCore.Components.IHandleAfterRender.OnAfterRenderAsync() { throw null; } - public System.Threading.Tasks.Task SetParametersAsync(Microsoft.AspNetCore.Components.ParameterView parameters) { throw null; } - } -} diff --git a/src/Components/Components/ref/Microsoft.AspNetCore.Components.netstandard2.0.Manual.cs b/src/Components/Components/ref/Microsoft.AspNetCore.Components.netstandard2.0.Manual.cs deleted file mode 100644 index 0f6b699935..0000000000 --- a/src/Components/Components/ref/Microsoft.AspNetCore.Components.netstandard2.0.Manual.cs +++ /dev/null @@ -1,58 +0,0 @@ -// 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.Runtime.InteropServices; -using Microsoft.AspNetCore.Components.Rendering; - -namespace Microsoft.AspNetCore.Components.RenderTree -{ - // https://github.com/dotnet/arcade/pull/2033 - [StructLayout(LayoutKind.Explicit, Pack = 4)] - public readonly partial struct RenderTreeFrame - { - [FieldOffset(0)] public readonly int Sequence; - - [FieldOffset(4)] public readonly RenderTreeFrameType FrameType; - - [FieldOffset(8)] public readonly int ElementSubtreeLength; - - [FieldOffset(16)] public readonly string ElementName; - - [FieldOffset(24)] public readonly object ElementKey; - - [FieldOffset(16)] public readonly string TextContent; - - [FieldOffset(8)] public readonly ulong AttributeEventHandlerId; - - [FieldOffset(16)] public readonly string AttributeName; - - [FieldOffset(24)] public readonly object AttributeValue; - - [FieldOffset(32)] public readonly string AttributeEventUpdatesAttributeName; - - [FieldOffset(8)] public readonly int ComponentSubtreeLength; - - [FieldOffset(12)] public readonly int ComponentId; - - [FieldOffset(16)] public readonly Type ComponentType; - - [FieldOffset(32)] public readonly object ComponentKey; - - public IComponent Component => null; - - [FieldOffset(8)] public readonly int RegionSubtreeLength; - - [FieldOffset(16)] public readonly string ElementReferenceCaptureId; - - [FieldOffset(24)] public readonly Action ElementReferenceCaptureAction; - - [FieldOffset(8)] public readonly int ComponentReferenceCaptureParentFrameIndex; - - [FieldOffset(16)] public readonly Action ComponentReferenceCaptureAction; - - [FieldOffset(16)] public readonly string MarkupContent; - - public override string ToString() => null; - } -} diff --git a/src/Components/Components/ref/Microsoft.AspNetCore.Components.netstandard2.0.cs b/src/Components/Components/ref/Microsoft.AspNetCore.Components.netstandard2.0.cs deleted file mode 100644 index c4a48435b4..0000000000 --- a/src/Components/Components/ref/Microsoft.AspNetCore.Components.netstandard2.0.cs +++ /dev/null @@ -1,550 +0,0 @@ -// 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. - -namespace Microsoft.AspNetCore.Components -{ - public static partial class BindConverter - { - public static bool FormatValue(bool value, System.Globalization.CultureInfo culture = null) { throw null; } - public static string FormatValue(System.DateTime value, System.Globalization.CultureInfo culture = null) { throw null; } - public static string FormatValue(System.DateTime value, string format, System.Globalization.CultureInfo culture = null) { throw null; } - public static string FormatValue(System.DateTimeOffset value, System.Globalization.CultureInfo culture = null) { throw null; } - public static string FormatValue(System.DateTimeOffset value, string format, System.Globalization.CultureInfo culture = null) { throw null; } - public static string FormatValue(decimal value, System.Globalization.CultureInfo culture = null) { throw null; } - public static string FormatValue(double value, System.Globalization.CultureInfo culture = null) { throw null; } - public static string FormatValue(int value, System.Globalization.CultureInfo culture = null) { throw null; } - public static string FormatValue(long value, System.Globalization.CultureInfo culture = null) { throw null; } - public static bool? FormatValue(bool? value, System.Globalization.CultureInfo culture = null) { throw null; } - public static string FormatValue(System.DateTimeOffset? value, System.Globalization.CultureInfo culture = null) { throw null; } - public static string FormatValue(System.DateTimeOffset? value, string format, System.Globalization.CultureInfo culture = null) { throw null; } - public static string FormatValue(System.DateTime? value, System.Globalization.CultureInfo culture = null) { throw null; } - public static string FormatValue(System.DateTime? value, string format, System.Globalization.CultureInfo culture = null) { throw null; } - public static string FormatValue(decimal? value, System.Globalization.CultureInfo culture = null) { throw null; } - public static string FormatValue(double? value, System.Globalization.CultureInfo culture = null) { throw null; } - public static string FormatValue(int? value, System.Globalization.CultureInfo culture = null) { throw null; } - public static string FormatValue(long? value, System.Globalization.CultureInfo culture = null) { throw null; } - public static string FormatValue(float? value, System.Globalization.CultureInfo culture = null) { throw null; } - public static string FormatValue(float value, System.Globalization.CultureInfo culture = null) { throw null; } - public static string FormatValue(string value, System.Globalization.CultureInfo culture = null) { throw null; } - public static object FormatValue(T value, System.Globalization.CultureInfo culture = null) { throw null; } - public static bool TryConvertToBool(object obj, System.Globalization.CultureInfo culture, out bool value) { throw null; } - public static bool TryConvertToDateTime(object obj, System.Globalization.CultureInfo culture, out System.DateTime value) { throw null; } - public static bool TryConvertToDateTime(object obj, System.Globalization.CultureInfo culture, string format, out System.DateTime value) { throw null; } - public static bool TryConvertToDateTimeOffset(object obj, System.Globalization.CultureInfo culture, out System.DateTimeOffset value) { throw null; } - public static bool TryConvertToDateTimeOffset(object obj, System.Globalization.CultureInfo culture, string format, out System.DateTimeOffset value) { throw null; } - public static bool TryConvertToDecimal(object obj, System.Globalization.CultureInfo culture, out decimal value) { throw null; } - public static bool TryConvertToDouble(object obj, System.Globalization.CultureInfo culture, out double value) { throw null; } - public static bool TryConvertToFloat(object obj, System.Globalization.CultureInfo culture, out float value) { throw null; } - public static bool TryConvertToInt(object obj, System.Globalization.CultureInfo culture, out int value) { throw null; } - public static bool TryConvertToLong(object obj, System.Globalization.CultureInfo culture, out long value) { throw null; } - public static bool TryConvertToNullableBool(object obj, System.Globalization.CultureInfo culture, out bool? value) { throw null; } - public static bool TryConvertToNullableDateTime(object obj, System.Globalization.CultureInfo culture, out System.DateTime? value) { throw null; } - public static bool TryConvertToNullableDateTime(object obj, System.Globalization.CultureInfo culture, string format, out System.DateTime? value) { throw null; } - public static bool TryConvertToNullableDateTimeOffset(object obj, System.Globalization.CultureInfo culture, out System.DateTimeOffset? value) { throw null; } - public static bool TryConvertToNullableDateTimeOffset(object obj, System.Globalization.CultureInfo culture, string format, out System.DateTimeOffset? value) { throw null; } - public static bool TryConvertToNullableDecimal(object obj, System.Globalization.CultureInfo culture, out decimal? value) { throw null; } - public static bool TryConvertToNullableDouble(object obj, System.Globalization.CultureInfo culture, out double? value) { throw null; } - public static bool TryConvertToNullableFloat(object obj, System.Globalization.CultureInfo culture, out float? value) { throw null; } - public static bool TryConvertToNullableInt(object obj, System.Globalization.CultureInfo culture, out int? value) { throw null; } - public static bool TryConvertToNullableLong(object obj, System.Globalization.CultureInfo culture, out long? value) { throw null; } - public static bool TryConvertToString(object obj, System.Globalization.CultureInfo culture, out string value) { throw null; } - public static bool TryConvertTo(object obj, System.Globalization.CultureInfo culture, out T value) { throw null; } - } - [System.AttributeUsageAttribute(System.AttributeTargets.Class, AllowMultiple=true, Inherited=true)] - public sealed partial class BindElementAttribute : System.Attribute - { - public BindElementAttribute(string element, string suffix, string valueAttribute, string changeAttribute) { } - public string ChangeAttribute { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - public string Element { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - public string Suffix { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - public string ValueAttribute { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - } - [System.AttributeUsageAttribute(System.AttributeTargets.Property, AllowMultiple=false, Inherited=true)] - public sealed partial class CascadingParameterAttribute : System.Attribute - { - public CascadingParameterAttribute() { } - public string Name { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } - } - public partial class CascadingValue : Microsoft.AspNetCore.Components.IComponent - { - public CascadingValue() { } - [Microsoft.AspNetCore.Components.ParameterAttribute] - public Microsoft.AspNetCore.Components.RenderFragment ChildContent { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } - [Microsoft.AspNetCore.Components.ParameterAttribute] - public bool IsFixed { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } - [Microsoft.AspNetCore.Components.ParameterAttribute] - public string Name { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } - [Microsoft.AspNetCore.Components.ParameterAttribute] - public TValue Value { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } - public void Attach(Microsoft.AspNetCore.Components.RenderHandle renderHandle) { } - public System.Threading.Tasks.Task SetParametersAsync(Microsoft.AspNetCore.Components.ParameterView parameters) { throw null; } - } - public partial class ChangeEventArgs : System.EventArgs - { - public ChangeEventArgs() { } - public object Value { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } - } - public abstract partial class ComponentBase : Microsoft.AspNetCore.Components.IComponent, Microsoft.AspNetCore.Components.IHandleAfterRender, Microsoft.AspNetCore.Components.IHandleEvent - { - public ComponentBase() { } - protected virtual void BuildRenderTree(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder builder) { } - protected System.Threading.Tasks.Task InvokeAsync(System.Action workItem) { throw null; } - protected System.Threading.Tasks.Task InvokeAsync(System.Func workItem) { throw null; } - void Microsoft.AspNetCore.Components.IComponent.Attach(Microsoft.AspNetCore.Components.RenderHandle renderHandle) { } - System.Threading.Tasks.Task Microsoft.AspNetCore.Components.IHandleAfterRender.OnAfterRenderAsync() { throw null; } - System.Threading.Tasks.Task Microsoft.AspNetCore.Components.IHandleEvent.HandleEventAsync(Microsoft.AspNetCore.Components.EventCallbackWorkItem callback, object arg) { throw null; } - protected virtual void OnAfterRender(bool firstRender) { } - protected virtual System.Threading.Tasks.Task OnAfterRenderAsync(bool firstRender) { throw null; } - protected virtual void OnInitialized() { } - protected virtual System.Threading.Tasks.Task OnInitializedAsync() { throw null; } - protected virtual void OnParametersSet() { } - protected virtual System.Threading.Tasks.Task OnParametersSetAsync() { throw null; } - public virtual System.Threading.Tasks.Task SetParametersAsync(Microsoft.AspNetCore.Components.ParameterView parameters) { throw null; } - protected virtual bool ShouldRender() { throw null; } - protected void StateHasChanged() { } - } - public abstract partial class Dispatcher - { - protected Dispatcher() { } - public void AssertAccess() { } - 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 workItem); - public abstract System.Threading.Tasks.Task InvokeAsync(System.Func> workItem); - public abstract System.Threading.Tasks.Task InvokeAsync(System.Func workItem); - protected void OnUnhandledException(System.UnhandledExceptionEventArgs e) { } - } - [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] - public readonly partial struct ElementReference - { - private readonly object _dummy; - public ElementReference(string id) { throw null; } - public string Id { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - } - [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] - public readonly partial struct EventCallback - { - private readonly object _dummy; - public static readonly Microsoft.AspNetCore.Components.EventCallback Empty; - public static readonly Microsoft.AspNetCore.Components.EventCallbackFactory Factory; - public EventCallback(Microsoft.AspNetCore.Components.IHandleEvent receiver, System.MulticastDelegate @delegate) { throw null; } - public bool HasDelegate { get { throw null; } } - public System.Threading.Tasks.Task InvokeAsync(object arg) { throw null; } - } - public sealed partial class EventCallbackFactory - { - public EventCallbackFactory() { } - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public Microsoft.AspNetCore.Components.EventCallback Create(object receiver, Microsoft.AspNetCore.Components.EventCallback callback) { throw null; } - public Microsoft.AspNetCore.Components.EventCallback Create(object receiver, System.Action callback) { throw null; } - public Microsoft.AspNetCore.Components.EventCallback Create(object receiver, System.Action callback) { throw null; } - public Microsoft.AspNetCore.Components.EventCallback Create(object receiver, System.Func callback) { throw null; } - public Microsoft.AspNetCore.Components.EventCallback Create(object receiver, System.Func callback) { throw null; } - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public Microsoft.AspNetCore.Components.EventCallback CreateInferred(object receiver, System.Action callback, TValue value) { throw null; } - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public Microsoft.AspNetCore.Components.EventCallback CreateInferred(object receiver, System.Func callback, TValue value) { throw null; } - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public Microsoft.AspNetCore.Components.EventCallback Create(object receiver, Microsoft.AspNetCore.Components.EventCallback callback) { throw null; } - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public Microsoft.AspNetCore.Components.EventCallback Create(object receiver, Microsoft.AspNetCore.Components.EventCallback callback) { throw null; } - public Microsoft.AspNetCore.Components.EventCallback Create(object receiver, System.Action callback) { throw null; } - public Microsoft.AspNetCore.Components.EventCallback Create(object receiver, System.Action callback) { throw null; } - public Microsoft.AspNetCore.Components.EventCallback Create(object receiver, System.Func callback) { throw null; } - public Microsoft.AspNetCore.Components.EventCallback Create(object receiver, System.Func callback) { throw null; } - } - public static partial class EventCallbackFactoryBinderExtensions - { - public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, bool existingValue, System.Globalization.CultureInfo culture = null) { throw null; } - public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, System.DateTimeOffset existingValue, System.Globalization.CultureInfo culture = null) { throw null; } - public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, System.DateTimeOffset existingValue, string format, System.Globalization.CultureInfo culture = null) { throw null; } - public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, System.DateTime existingValue, System.Globalization.CultureInfo culture = null) { throw null; } - public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, System.DateTime existingValue, string format, System.Globalization.CultureInfo culture = null) { throw null; } - public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, decimal existingValue, System.Globalization.CultureInfo culture = null) { throw null; } - public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, double existingValue, System.Globalization.CultureInfo culture = null) { throw null; } - public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, int existingValue, System.Globalization.CultureInfo culture = null) { throw null; } - public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, long existingValue, System.Globalization.CultureInfo culture = null) { throw null; } - public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, bool? existingValue, System.Globalization.CultureInfo culture = null) { throw null; } - public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, System.DateTimeOffset? existingValue, System.Globalization.CultureInfo culture = null) { throw null; } - public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, System.DateTimeOffset? existingValue, string format, System.Globalization.CultureInfo culture = null) { throw null; } - public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, System.DateTime? existingValue, System.Globalization.CultureInfo culture = null) { throw null; } - public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, System.DateTime? existingValue, string format, System.Globalization.CultureInfo culture = null) { throw null; } - public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, decimal? existingValue, System.Globalization.CultureInfo culture = null) { throw null; } - public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, double? existingValue, System.Globalization.CultureInfo culture = null) { throw null; } - public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, int? existingValue, System.Globalization.CultureInfo culture = null) { throw null; } - public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, long? existingValue, System.Globalization.CultureInfo culture = null) { throw null; } - public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, float? existingValue, System.Globalization.CultureInfo culture = null) { throw null; } - public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, float existingValue, System.Globalization.CultureInfo culture = null) { throw null; } - public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, string existingValue, System.Globalization.CultureInfo culture = null) { throw null; } - public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, T existingValue, System.Globalization.CultureInfo culture = null) { throw null; } - } - public static partial class EventCallbackFactoryEventArgsExtensions - { - public static Microsoft.AspNetCore.Components.EventCallback Create(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action callback) { throw null; } - public static Microsoft.AspNetCore.Components.EventCallback Create(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action callback) { throw null; } - public static Microsoft.AspNetCore.Components.EventCallback Create(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Func callback) { throw null; } - public static Microsoft.AspNetCore.Components.EventCallback Create(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Func callback) { throw null; } - } - [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] - public readonly partial struct EventCallbackWorkItem - { - private readonly object _dummy; - public static readonly Microsoft.AspNetCore.Components.EventCallbackWorkItem Empty; - public EventCallbackWorkItem(System.MulticastDelegate @delegate) { throw null; } - public System.Threading.Tasks.Task InvokeAsync(object arg) { throw null; } - } - [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] - public readonly partial struct EventCallback - { - private readonly object _dummy; - public static readonly Microsoft.AspNetCore.Components.EventCallback Empty; - public EventCallback(Microsoft.AspNetCore.Components.IHandleEvent receiver, System.MulticastDelegate @delegate) { throw null; } - public bool HasDelegate { get { throw null; } } - public System.Threading.Tasks.Task InvokeAsync(TValue arg) { throw null; } - } - [System.AttributeUsageAttribute(System.AttributeTargets.Class, AllowMultiple=true, Inherited=true)] - public sealed partial class EventHandlerAttribute : System.Attribute - { - public EventHandlerAttribute(string attributeName, System.Type eventArgsType) { } - public EventHandlerAttribute(string attributeName, System.Type eventArgsType, bool enableStopPropagation, bool enablePreventDefault) { } - public string AttributeName { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - public bool EnablePreventDefault { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - public bool EnableStopPropagation { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - public System.Type EventArgsType { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - } - public partial interface IComponent - { - void Attach(Microsoft.AspNetCore.Components.RenderHandle renderHandle); - System.Threading.Tasks.Task SetParametersAsync(Microsoft.AspNetCore.Components.ParameterView parameters); - } - public partial interface IHandleAfterRender - { - System.Threading.Tasks.Task OnAfterRenderAsync(); - } - public partial interface IHandleEvent - { - System.Threading.Tasks.Task HandleEventAsync(Microsoft.AspNetCore.Components.EventCallbackWorkItem item, object arg); - } - [System.AttributeUsageAttribute(System.AttributeTargets.Property, AllowMultiple=false, Inherited=true)] - public sealed partial class InjectAttribute : System.Attribute - { - public InjectAttribute() { } - } - [System.AttributeUsageAttribute(System.AttributeTargets.Class, AllowMultiple=false, Inherited=true)] - public sealed partial class LayoutAttribute : System.Attribute - { - public LayoutAttribute(System.Type layoutType) { } - public System.Type LayoutType { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - } - public abstract partial class LayoutComponentBase : Microsoft.AspNetCore.Components.ComponentBase - { - protected LayoutComponentBase() { } - [Microsoft.AspNetCore.Components.ParameterAttribute] - public Microsoft.AspNetCore.Components.RenderFragment Body { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } - } - public partial class LayoutView : Microsoft.AspNetCore.Components.IComponent - { - public LayoutView() { } - [Microsoft.AspNetCore.Components.ParameterAttribute] - public Microsoft.AspNetCore.Components.RenderFragment ChildContent { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } - [Microsoft.AspNetCore.Components.ParameterAttribute] - public System.Type Layout { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } - public void Attach(Microsoft.AspNetCore.Components.RenderHandle renderHandle) { } - public System.Threading.Tasks.Task SetParametersAsync(Microsoft.AspNetCore.Components.ParameterView parameters) { throw null; } - } - public sealed partial class LocationChangeException : System.Exception - { - public LocationChangeException(string message, System.Exception innerException) { } - } - [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] - public readonly partial struct MarkupString - { - private readonly object _dummy; - public MarkupString(string value) { throw null; } - public string Value { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - public static explicit operator Microsoft.AspNetCore.Components.MarkupString (string value) { throw null; } - public override string ToString() { throw null; } - } - public partial class NavigationException : System.Exception - { - public NavigationException(string uri) { } - public string Location { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - } - public abstract partial class NavigationManager - { - protected NavigationManager() { } - public string BaseUri { get { throw null; } protected set { } } - public string Uri { get { throw null; } protected set { } } - public event System.EventHandler LocationChanged { add { } remove { } } - protected virtual void EnsureInitialized() { } - protected void Initialize(string baseUri, string uri) { } - public void NavigateTo(string uri, bool forceLoad = false) { } - protected abstract void NavigateToCore(string uri, bool forceLoad); - protected void NotifyLocationChanged(bool isInterceptedLink) { } - public System.Uri ToAbsoluteUri(string relativeUri) { throw null; } - public string ToBaseRelativePath(string uri) { throw null; } - } - public abstract partial class OwningComponentBase : Microsoft.AspNetCore.Components.ComponentBase, System.IDisposable - { - protected OwningComponentBase() { } - protected bool IsDisposed { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - protected System.IServiceProvider ScopedServices { get { throw null; } } - protected virtual void Dispose(bool disposing) { } - void System.IDisposable.Dispose() { } - } - public abstract partial class OwningComponentBase : Microsoft.AspNetCore.Components.OwningComponentBase, System.IDisposable - { - protected OwningComponentBase() { } - protected TService Service { get { throw null; } } - } - [System.AttributeUsageAttribute(System.AttributeTargets.Property, AllowMultiple=false, Inherited=true)] - public sealed partial class ParameterAttribute : System.Attribute - { - public ParameterAttribute() { } - public bool CaptureUnmatchedValues { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } - } - [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] - public readonly partial struct ParameterValue - { - private readonly object _dummy; - private readonly int _dummyPrimitive; - public bool Cascading { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - public string Name { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - public object Value { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - } - [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] - public readonly partial struct ParameterView - { - private readonly object _dummy; - private readonly int _dummyPrimitive; - public static Microsoft.AspNetCore.Components.ParameterView Empty { get { throw null; } } - public static Microsoft.AspNetCore.Components.ParameterView FromDictionary(System.Collections.Generic.IDictionary parameters) { throw null; } - public Microsoft.AspNetCore.Components.ParameterView.Enumerator GetEnumerator() { throw null; } - public TValue GetValueOrDefault(string parameterName) { throw null; } - public TValue GetValueOrDefault(string parameterName, TValue defaultValue) { throw null; } - public void SetParameterProperties(object target) { } - public System.Collections.Generic.IReadOnlyDictionary ToDictionary() { throw null; } - public bool TryGetValue(string parameterName, out TValue result) { throw null; } - [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] - public partial struct Enumerator - { - private object _dummy; - private int _dummyPrimitive; - public Microsoft.AspNetCore.Components.ParameterValue Current { get { throw null; } } - public bool MoveNext() { throw null; } - } - } - public delegate void RenderFragment(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder builder); - public delegate Microsoft.AspNetCore.Components.RenderFragment RenderFragment(TValue value); - [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] - public readonly partial struct RenderHandle - { - private readonly object _dummy; - private readonly int _dummyPrimitive; - public Microsoft.AspNetCore.Components.Dispatcher Dispatcher { get { throw null; } } - public bool IsInitialized { get { throw null; } } - public void Render(Microsoft.AspNetCore.Components.RenderFragment renderFragment) { } - } - [System.AttributeUsageAttribute(System.AttributeTargets.Class, AllowMultiple=true, Inherited=false)] - public sealed partial class RouteAttribute : System.Attribute - { - public RouteAttribute(string template) { } - public string Template { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - } - public sealed partial class RouteData - { - public RouteData(System.Type pageType, System.Collections.Generic.IReadOnlyDictionary routeValues) { } - public System.Type PageType { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - public System.Collections.Generic.IReadOnlyDictionary RouteValues { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - } - public partial class RouteView : Microsoft.AspNetCore.Components.IComponent - { - public RouteView() { } - [Microsoft.AspNetCore.Components.ParameterAttribute] - public System.Type DefaultLayout { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } - [Microsoft.AspNetCore.Components.ParameterAttribute] - public Microsoft.AspNetCore.Components.RouteData RouteData { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } - public void Attach(Microsoft.AspNetCore.Components.RenderHandle renderHandle) { } - protected virtual void Render(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder builder) { } - public System.Threading.Tasks.Task SetParametersAsync(Microsoft.AspNetCore.Components.ParameterView parameters) { throw null; } - } -} -namespace Microsoft.AspNetCore.Components.CompilerServices -{ - public static partial class RuntimeHelpers - { - public static Microsoft.AspNetCore.Components.EventCallback CreateInferredEventCallback(object receiver, System.Action callback, T value) { throw null; } - public static Microsoft.AspNetCore.Components.EventCallback CreateInferredEventCallback(object receiver, System.Func callback, T value) { throw null; } - public static T TypeCheck(T value) { throw null; } - } -} -namespace Microsoft.AspNetCore.Components.Rendering -{ - public sealed partial class RenderTreeBuilder : System.IDisposable - { - public RenderTreeBuilder() { } - public void AddAttribute(int sequence, in Microsoft.AspNetCore.Components.RenderTree.RenderTreeFrame frame) { } - public void AddAttribute(int sequence, string name, Microsoft.AspNetCore.Components.EventCallback value) { } - public void AddAttribute(int sequence, string name, bool value) { } - public void AddAttribute(int sequence, string name, System.MulticastDelegate value) { } - public void AddAttribute(int sequence, string name, object value) { } - public void AddAttribute(int sequence, string name, string value) { } - public void AddAttribute(int sequence, string name, Microsoft.AspNetCore.Components.EventCallback value) { } - public void AddComponentReferenceCapture(int sequence, System.Action componentReferenceCaptureAction) { } - public void AddContent(int sequence, Microsoft.AspNetCore.Components.MarkupString markupContent) { } - public void AddContent(int sequence, Microsoft.AspNetCore.Components.RenderFragment fragment) { } - public void AddContent(int sequence, object textContent) { } - public void AddContent(int sequence, string textContent) { } - public void AddContent(int sequence, Microsoft.AspNetCore.Components.RenderFragment fragment, TValue value) { } - public void AddElementReferenceCapture(int sequence, System.Action elementReferenceCaptureAction) { } - public void AddMarkupContent(int sequence, string markupContent) { } - public void AddMultipleAttributes(int sequence, System.Collections.Generic.IEnumerable> attributes) { } - public void Clear() { } - public void CloseComponent() { } - public void CloseElement() { } - public void CloseRegion() { } - public Microsoft.AspNetCore.Components.RenderTree.ArrayRange GetFrames() { throw null; } - public void OpenComponent(int sequence, System.Type componentType) { } - public void OpenComponent(int sequence) where TComponent : Microsoft.AspNetCore.Components.IComponent { } - public void OpenElement(int sequence, string elementName) { } - public void OpenRegion(int sequence) { } - public void SetKey(object value) { } - public void SetUpdatesAttributeName(string updatesAttributeName) { } - void System.IDisposable.Dispose() { } - } -} -namespace Microsoft.AspNetCore.Components.RenderTree -{ - [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] - public readonly partial struct ArrayBuilderSegment : System.Collections.Generic.IEnumerable, System.Collections.IEnumerable - { - private readonly object _dummy; - private readonly int _dummyPrimitive; - public T[] Array { get { throw null; } } - public int Count { get { throw null; } } - public T this[int index] { get { throw null; } } - public int Offset { get { throw null; } } - System.Collections.Generic.IEnumerator System.Collections.Generic.IEnumerable.GetEnumerator() { throw null; } - System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { throw null; } - } - [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] - public readonly partial struct ArrayRange - { - public readonly T[] Array; - public readonly int Count; - public ArrayRange(T[] array, int count) { throw null; } - public Microsoft.AspNetCore.Components.RenderTree.ArrayRange Clone() { throw null; } - } - public partial class EventFieldInfo - { - public EventFieldInfo() { } - public int ComponentId { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } - public object FieldValue { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } - } - [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] - public readonly partial struct RenderBatch - { - private readonly object _dummy; - public Microsoft.AspNetCore.Components.RenderTree.ArrayRange DisposedComponentIDs { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - public Microsoft.AspNetCore.Components.RenderTree.ArrayRange DisposedEventHandlerIDs { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - public Microsoft.AspNetCore.Components.RenderTree.ArrayRange ReferenceFrames { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - public Microsoft.AspNetCore.Components.RenderTree.ArrayRange UpdatedComponents { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - } - public abstract partial class Renderer : System.IDisposable - { - public Renderer(System.IServiceProvider serviceProvider, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) { } - public abstract Microsoft.AspNetCore.Components.Dispatcher Dispatcher { get; } - public event System.UnhandledExceptionEventHandler UnhandledSynchronizationException { add { } remove { } } - protected internal int AssignRootComponentId(Microsoft.AspNetCore.Components.IComponent component) { throw null; } - public virtual System.Threading.Tasks.Task DispatchEventAsync(ulong eventHandlerId, Microsoft.AspNetCore.Components.RenderTree.EventFieldInfo fieldInfo, System.EventArgs eventArgs) { throw null; } - public void Dispose() { } - protected virtual void Dispose(bool disposing) { } - protected Microsoft.AspNetCore.Components.RenderTree.ArrayRange GetCurrentRenderTreeFrames(int componentId) { throw null; } - protected abstract void HandleException(System.Exception exception); - protected Microsoft.AspNetCore.Components.IComponent InstantiateComponent(System.Type componentType) { throw null; } - protected virtual void ProcessPendingRender() { } - protected System.Threading.Tasks.Task RenderRootComponentAsync(int componentId) { throw null; } - [System.Diagnostics.DebuggerStepThroughAttribute] - protected System.Threading.Tasks.Task RenderRootComponentAsync(int componentId, Microsoft.AspNetCore.Components.ParameterView initialParameters) { throw null; } - protected abstract System.Threading.Tasks.Task UpdateDisplayAsync(in Microsoft.AspNetCore.Components.RenderTree.RenderBatch renderBatch); - } - [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] - public readonly partial struct RenderTreeDiff - { - public readonly int ComponentId; - public readonly Microsoft.AspNetCore.Components.RenderTree.ArrayBuilderSegment Edits; - } - [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Explicit)] - public readonly partial struct RenderTreeEdit - { - [System.Runtime.InteropServices.FieldOffsetAttribute(8)] - public readonly int MoveToSiblingIndex; - [System.Runtime.InteropServices.FieldOffsetAttribute(8)] - public readonly int ReferenceFrameIndex; - [System.Runtime.InteropServices.FieldOffsetAttribute(16)] - public readonly string RemovedAttributeName; - [System.Runtime.InteropServices.FieldOffsetAttribute(4)] - public readonly int SiblingIndex; - [System.Runtime.InteropServices.FieldOffsetAttribute(0)] - public readonly Microsoft.AspNetCore.Components.RenderTree.RenderTreeEditType Type; - } - public enum RenderTreeEditType - { - PrependFrame = 1, - RemoveFrame = 2, - SetAttribute = 3, - RemoveAttribute = 4, - UpdateText = 5, - StepIn = 6, - StepOut = 7, - UpdateMarkup = 8, - PermutationListEntry = 9, - PermutationListEnd = 10, - } - public enum RenderTreeFrameType : short - { - None = (short)0, - Element = (short)1, - Text = (short)2, - Attribute = (short)3, - Component = (short)4, - Region = (short)5, - ElementReferenceCapture = (short)6, - ComponentReferenceCapture = (short)7, - Markup = (short)8, - } -} -namespace Microsoft.AspNetCore.Components.Routing -{ - public partial interface IHostEnvironmentNavigationManager - { - void Initialize(string baseUri, string uri); - } - public partial interface INavigationInterception - { - System.Threading.Tasks.Task EnableNavigationInterceptionAsync(); - } - public partial class LocationChangedEventArgs : System.EventArgs - { - public LocationChangedEventArgs(string location, bool isNavigationIntercepted) { } - public bool IsNavigationIntercepted { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - public string Location { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - } - public partial class Router : Microsoft.AspNetCore.Components.IComponent, Microsoft.AspNetCore.Components.IHandleAfterRender, System.IDisposable - { - public Router() { } - [Microsoft.AspNetCore.Components.ParameterAttribute] - public System.Collections.Generic.IEnumerable AdditionalAssemblies { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } - [Microsoft.AspNetCore.Components.ParameterAttribute] - public System.Reflection.Assembly AppAssembly { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } - [Microsoft.AspNetCore.Components.ParameterAttribute] - public Microsoft.AspNetCore.Components.RenderFragment Found { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } - [Microsoft.AspNetCore.Components.ParameterAttribute] - public Microsoft.AspNetCore.Components.RenderFragment NotFound { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } - public void Attach(Microsoft.AspNetCore.Components.RenderHandle renderHandle) { } - public void Dispose() { } - System.Threading.Tasks.Task Microsoft.AspNetCore.Components.IHandleAfterRender.OnAfterRenderAsync() { throw null; } - public System.Threading.Tasks.Task SetParametersAsync(Microsoft.AspNetCore.Components.ParameterView parameters) { throw null; } - } -} diff --git a/src/Components/Components/src/BindConverter.cs b/src/Components/Components/src/BindConverter.cs deleted file mode 100644 index f77689bde2..0000000000 --- a/src/Components/Components/src/BindConverter.cs +++ /dev/null @@ -1,1418 +0,0 @@ -// 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.Collections.Concurrent; -using System.ComponentModel; -using System.Globalization; -using System.Reflection; - -namespace Microsoft.AspNetCore.Components -{ - /// - /// Performs conversions during binding. - /// - // - // Perf: our conversion routines present a regular API surface that allows us to specialize on types to avoid boxing. - // for instance, many of these types could be cast to IFormattable to do the appropriate formatting, but that's going - // to allocate. - public static class BindConverter - { - private static object BoxedTrue = true; - private static object BoxedFalse = false; - - private delegate object BindFormatter(T value, CultureInfo culture); - private delegate object BindFormatterWithFormat(T value, CultureInfo culture, string format); - - internal delegate bool BindParser(object obj, CultureInfo culture, out T value); - internal delegate bool BindParserWithFormat(object obj, CultureInfo culture, string format, out T value); - - /// - /// Formats the provided as a . - /// - /// The value to format. - /// - /// The to use while formatting. Defaults to . - /// - /// The formatted value. - public static string FormatValue(string value, CultureInfo culture = null) => FormatStringValueCore(value, culture); - - private static string FormatStringValueCore(string value, CultureInfo culture) - { - return value; - } - - /// - /// Formats the provided for inclusion in an attribute. - /// - /// The value to format. - /// - /// The to use while formatting. Defaults to . - /// - /// The formatted value. - public static bool FormatValue(bool value, CultureInfo culture = null) - { - // Formatting for bool is special-cased. We need to produce a boolean value for conditional attributes - // to work. - return value; - } - - // Used with generics - private static object FormatBoolValueCore(bool value, CultureInfo culture) - { - // Formatting for bool is special-cased. We need to produce a boolean value for conditional attributes - // to work. - return value ? BoxedTrue : BoxedFalse; - } - - /// - /// Formats the provided for inclusion in an attribute. - /// - /// The value to format. - /// - /// The to use while formatting. Defaults to . - /// - /// The formatted value. - public static bool? FormatValue(bool? value, CultureInfo culture = null) - { - // Formatting for bool is special-cased. We need to produce a boolean value for conditional attributes - // to work. - return value == null ? (bool?)null : value.Value; - } - - // Used with generics - private static object FormatNullableBoolValueCore(bool? value, CultureInfo culture) - { - // Formatting for bool is special-cased. We need to produce a boolean value for conditional attributes - // to work. - return value == null ? null : value.Value ? BoxedTrue : BoxedFalse; - } - - /// - /// Formats the provided for inclusion in an attribute. - /// - /// The value to format. - /// - /// The to use while formatting. Defaults to . - /// - /// The formatted value. - public static string FormatValue(int value, CultureInfo culture = null) => FormatIntValueCore(value, culture); - - private static string FormatIntValueCore(int value, CultureInfo culture) - { - return value.ToString(culture ?? CultureInfo.CurrentCulture); - } - - /// - /// Formats the provided for inclusion in an attribute. - /// - /// The value to format. - /// - /// The to use while formatting. Defaults to . - /// - /// The formatted value. - public static string FormatValue(int? value, CultureInfo culture = null) => FormatNullableIntValueCore(value, culture); - - private static string FormatNullableIntValueCore(int? value, CultureInfo culture) - { - if (value == null) - { - return null; - } - - return value.Value.ToString(culture ?? CultureInfo.CurrentCulture); - } - - /// - /// Formats the provided for inclusion in an attribute. - /// - /// The value to format. - /// - /// The to use while formatting. Defaults to . - /// - /// The formatted value. - public static string FormatValue(long value, CultureInfo culture = null) => FormatLongValueCore(value, culture); - - private static string FormatLongValueCore(long value, CultureInfo culture) - { - return value.ToString(culture ?? CultureInfo.CurrentCulture); - } - - /// - /// Formats the provided for inclusion in an attribute. - /// - /// The value to format. - /// - /// The to use while formatting. Defaults to . - /// - /// The formatted value. - public static string FormatValue(long? value, CultureInfo culture = null) => FormatNullableLongValueCore(value, culture); - - private static string FormatNullableLongValueCore(long? value, CultureInfo culture) - { - if (value == null) - { - return null; - } - - return value.Value.ToString(culture ?? CultureInfo.CurrentCulture); - } - - /// - /// Formats the provided for inclusion in an attribute. - /// - /// The value to format. - /// - /// The to use while formatting. Defaults to . - /// - /// The formatted value. - public static string FormatValue(float value, CultureInfo culture = null) => FormatFloatValueCore(value, culture); - - private static string FormatFloatValueCore(float value, CultureInfo culture) - { - return value.ToString(culture ?? CultureInfo.CurrentCulture); - } - - /// - /// Formats the provided for inclusion in an attribute. - /// - /// The value to format. - /// - /// The to use while formatting. Defaults to . - /// - /// The formatted value. - public static string FormatValue(float? value, CultureInfo culture = null) => FormatNullableFloatValueCore(value, culture); - - private static string FormatNullableFloatValueCore(float? value, CultureInfo culture) - { - if (value == null) - { - return null; - } - - return value.Value.ToString(culture ?? CultureInfo.CurrentCulture); - } - - /// - /// Formats the provided for inclusion in an attribute. - /// - /// The value to format. - /// - /// The to use while formatting. Defaults to . - /// - /// The formatted value. - public static string FormatValue(double value, CultureInfo culture = null) => FormatDoubleValueCore(value, culture); - - private static string FormatDoubleValueCore(double value, CultureInfo culture) - { - return value.ToString(culture ?? CultureInfo.CurrentCulture); - } - - /// - /// Formats the provided for inclusion in an attribute. - /// - /// The value to format. - /// - /// The to use while formatting. Defaults to . - /// - /// The formatted value. - public static string FormatValue(double? value, CultureInfo culture = null) => FormatNullableDoubleValueCore(value, culture); - - private static string FormatNullableDoubleValueCore(double? value, CultureInfo culture) - { - if (value == null) - { - return null; - } - - return value.Value.ToString(culture ?? CultureInfo.CurrentCulture); - } - - /// - /// Formats the provided for inclusion in an attribute. - /// - /// The value to format. - /// - /// The to use while formatting. Defaults to . - /// - /// The formatted value. - public static string FormatValue(decimal value, CultureInfo culture = null) => FormatDecimalValueCore(value, culture); - - private static string FormatDecimalValueCore(decimal value, CultureInfo culture) - { - return value.ToString(culture ?? CultureInfo.CurrentCulture); - } - - /// - /// Formats the provided as a . - /// - /// The value to format. - /// - /// The to use while formatting. Defaults to . - /// - /// The formatted value. - public static string FormatValue(decimal? value, CultureInfo culture = null) => FormatNullableDecimalValueCore(value, culture); - - private static string FormatNullableDecimalValueCore(decimal? value, CultureInfo culture) - { - if (value == null) - { - return null; - } - - return value.Value.ToString(culture ?? CultureInfo.CurrentCulture); - } - - /// - /// Formats the provided as a . - /// - /// The value to format. - /// - /// The to use while formatting. Defaults to . - /// - /// The formatted value. - public static string FormatValue(DateTime value, CultureInfo culture = null) => FormatDateTimeValueCore(value, format: null, culture); - - /// - /// Formats the provided as a . - /// - /// The value to format. - /// The format to use. Provided to . - /// - /// The to use while formatting. Defaults to . - /// - /// The formatted value. - public static string FormatValue(DateTime value, string format, CultureInfo culture = null) => FormatDateTimeValueCore(value, format, culture); - - private static string FormatDateTimeValueCore(DateTime value, string format, CultureInfo culture) - { - if (format != null) - { - return value.ToString(format, culture ?? CultureInfo.CurrentCulture); - } - - return value.ToString(culture ?? CultureInfo.CurrentCulture); - } - - private static string FormatDateTimeValueCore(DateTime value, CultureInfo culture) - { - return value.ToString(culture ?? CultureInfo.CurrentCulture); - } - - /// - /// Formats the provided as a . - /// - /// The value to format. - /// - /// The to use while formatting. Defaults to . - /// - /// The formatted value. - public static string FormatValue(DateTime? value, CultureInfo culture = null) => FormatNullableDateTimeValueCore(value, format: null, culture); - - /// - /// Formats the provided as a . - /// - /// The value to format. - /// The format to use. Provided to . - /// - /// The to use while formatting. Defaults to . - /// - /// The formatted value. - public static string FormatValue(DateTime? value, string format, CultureInfo culture = null) => FormatNullableDateTimeValueCore(value, format, culture); - - private static string FormatNullableDateTimeValueCore(DateTime? value, string format, CultureInfo culture) - { - if (value == null) - { - return null; - } - - if (format != null) - { - return value.Value.ToString(format, culture ?? CultureInfo.CurrentCulture); - } - - return value.Value.ToString(culture ?? CultureInfo.CurrentCulture); - } - - private static string FormatNullableDateTimeValueCore(DateTime? value, CultureInfo culture) - { - if (value == null) - { - return null; - } - - return value.Value.ToString(culture ?? CultureInfo.CurrentCulture); - } - - /// - /// Formats the provided as a . - /// - /// The value to format. - /// - /// The to use while formatting. Defaults to . - /// - /// The formatted value. - public static string FormatValue(DateTimeOffset value, CultureInfo culture = null) => FormatDateTimeOffsetValueCore(value, format: null, culture); - - - /// - /// Formats the provided as a . - /// - /// The value to format. - /// The format to use. Provided to . - /// - /// The to use while formatting. Defaults to . - /// - /// The formatted value. - public static string FormatValue(DateTimeOffset value, string format, CultureInfo culture = null) => FormatDateTimeOffsetValueCore(value, format, culture); - - private static string FormatDateTimeOffsetValueCore(DateTimeOffset value, string format, CultureInfo culture) - { - if (format != null) - { - return value.ToString(format, culture ?? CultureInfo.CurrentCulture); - } - - return value.ToString(culture ?? CultureInfo.CurrentCulture); - } - - private static string FormatDateTimeOffsetValueCore(DateTimeOffset value, CultureInfo culture) - { - return value.ToString(culture ?? CultureInfo.CurrentCulture); - } - - /// - /// Formats the provided as a . - /// - /// The value to format. - /// - /// The to use while formatting. Defaults to . - /// - /// The formatted value. - public static string FormatValue(DateTimeOffset? value, CultureInfo culture = null) => FormatNullableDateTimeOffsetValueCore(value, format: null, culture); - - /// - /// Formats the provided as a . - /// - /// The value to format. - /// The format to use. Provided to . - /// - /// The to use while formatting. Defaults to . - /// - /// The formatted value. - public static string FormatValue(DateTimeOffset? value, string format, CultureInfo culture = null) => FormatNullableDateTimeOffsetValueCore(value, format, culture); - - private static string FormatNullableDateTimeOffsetValueCore(DateTimeOffset? value, string format, CultureInfo culture) - { - if (value == null) - { - return null; - } - - if (format != null) - { - return value.Value.ToString(format, culture ?? CultureInfo.CurrentCulture); - } - - return value.Value.ToString(culture ?? CultureInfo.CurrentCulture); - } - - private static string FormatNullableDateTimeOffsetValueCore(DateTimeOffset? value, CultureInfo culture) - { - if (value == null) - { - return null; - } - - return value.Value.ToString(culture ?? CultureInfo.CurrentCulture); - } - - private static string FormatEnumValueCore(T value, CultureInfo culture) where T : struct, Enum - { - return value.ToString(); // The overload that acccepts a culture is [Obsolete] - } - - private static string FormatNullableEnumValueCore(T? value, CultureInfo culture) where T : struct, Enum - { - if (value == null) - { - return null; - } - - return value.Value.ToString(); // The overload that acccepts a culture is [Obsolete] - } - - /// - /// Formats the provided as a . - /// - /// The value to format. - /// - /// The to use while formatting. Defaults to . - /// - /// The formatted value. - public static object FormatValue(T value, CultureInfo culture = null) - { - var formatter = FormatterDelegateCache.Get(); - return formatter(value, culture); - } - - /// - /// Attempts to convert a value to a . - /// - /// The object to convert. - /// The to use for conversion. - /// The converted value. - /// true if conversion is successful, otherwise false. - public static bool TryConvertToString(object obj, CultureInfo culture, out string value) - { - return ConvertToStringCore(obj, culture, out value); - } - - internal readonly static BindParser ConvertToString = ConvertToStringCore; - - private static bool ConvertToStringCore(object obj, CultureInfo culture, out string value) - { - // We expect the input to already be a string. - value = (string)obj; - return true; - } - - /// - /// Attempts to convert a value to a . - /// - /// The object to convert. - /// The to use for conversion. - /// The converted value. - /// true if conversion is successful, otherwise false. - public static bool TryConvertToBool(object obj, CultureInfo culture, out bool value) - { - return ConvertToBoolCore(obj, culture, out value); - } - - /// - /// Attempts to convert a value to a nullable . - /// - /// The object to convert. - /// The to use for conversion. - /// The converted value. - /// true if conversion is successful, otherwise false. - public static bool TryConvertToNullableBool(object obj, CultureInfo culture, out bool? value) - { - return ConvertToNullableBoolCore(obj, culture, out value); - } - - internal static BindParser ConvertToBool = ConvertToBoolCore; - internal static BindParser ConvertToNullableBool = ConvertToNullableBoolCore; - - private static bool ConvertToBoolCore(object obj, CultureInfo culture, out bool value) - { - // We expect the input to already be a bool. - value = (bool)obj; - return true; - } - - private static bool ConvertToNullableBoolCore(object obj, CultureInfo culture, out bool? value) - { - // We expect the input to already be a bool. - value = (bool?)obj; - return true; - } - - /// - /// Attempts to convert a value to a . - /// - /// The object to convert. - /// The to use for conversion. - /// The converted value. - /// true if conversion is successful, otherwise false. - public static bool TryConvertToInt(object obj, CultureInfo culture, out int value) - { - return ConvertToIntCore(obj, culture, out value); - } - - /// - /// Attempts to convert a value to a nullable . - /// - /// The object to convert. - /// The to use for conversion. - /// The converted value. - /// true if conversion is successful, otherwise false. - public static bool TryConvertToNullableInt(object obj, CultureInfo culture, out int? value) - { - return ConvertToNullableIntCore(obj, culture, out value); - } - - internal static BindParser ConvertToInt = ConvertToIntCore; - internal static BindParser ConvertToNullableInt = ConvertToNullableIntCore; - - private static bool ConvertToIntCore(object obj, CultureInfo culture, out int value) - { - var text = (string)obj; - if (string.IsNullOrEmpty(text)) - { - value = default; - return false; - } - - if (!int.TryParse(text, NumberStyles.Number, culture ?? CultureInfo.CurrentCulture, out var converted)) - { - value = default; - return false; - } - - value = converted; - return true; - } - - private static bool ConvertToNullableIntCore(object obj, CultureInfo culture, out int? value) - { - var text = (string)obj; - if (string.IsNullOrEmpty(text)) - { - value = default; - return true; - } - - if (!int.TryParse(text, NumberStyles.Number, culture ?? CultureInfo.CurrentCulture, out var converted)) - { - value = default; - return false; - } - - value = converted; - return true; - } - - /// - /// Attempts to convert a value to a . - /// - /// The object to convert. - /// The to use for conversion. - /// The converted value. - /// true if conversion is successful, otherwise false. - public static bool TryConvertToLong(object obj, CultureInfo culture, out long value) - { - return ConvertToLongCore(obj, culture, out value); - } - - /// - /// Attempts to convert a value to a nullable . - /// - /// The object to convert. - /// The to use for conversion. - /// The converted value. - /// true if conversion is successful, otherwise false. - public static bool TryConvertToNullableLong(object obj, CultureInfo culture, out long? value) - { - return ConvertToNullableLongCore(obj, culture, out value); - } - - internal static BindParser ConvertToLong = ConvertToLongCore; - internal static BindParser ConvertToNullableLong = ConvertToNullableLongCore; - - private static bool ConvertToLongCore(object obj, CultureInfo culture, out long value) - { - var text = (string)obj; - if (string.IsNullOrEmpty(text)) - { - value = default; - return false; - } - - if (!long.TryParse(text, NumberStyles.Number, culture ?? CultureInfo.CurrentCulture, out var converted)) - { - value = default; - return false; - } - - value = converted; - return true; - } - - private static bool ConvertToNullableLongCore(object obj, CultureInfo culture, out long? value) - { - var text = (string)obj; - if (string.IsNullOrEmpty(text)) - { - value = default; - return true; - } - - if (!long.TryParse(text, NumberStyles.Number, culture ?? CultureInfo.CurrentCulture, out var converted)) - { - value = default; - return false; - } - - value = converted; - return true; - } - - /// - /// Attempts to convert a value to a . - /// - /// The object to convert. - /// The to use for conversion. - /// The converted value. - /// true if conversion is successful, otherwise false. - public static bool TryConvertToFloat(object obj, CultureInfo culture, out float value) - { - return ConvertToFloatCore(obj, culture, out value); - } - - /// - /// Attempts to convert a value to a nullable . - /// - /// The object to convert. - /// The to use for conversion. - /// The converted value. - /// true if conversion is successful, otherwise false. - public static bool TryConvertToNullableFloat(object obj, CultureInfo culture, out float? value) - { - return ConvertToNullableFloatCore(obj, culture, out value); - } - - internal static BindParser ConvertToFloat = ConvertToFloatCore; - internal static BindParser ConvertToNullableFloat = ConvertToNullableFloatCore; - - private static bool ConvertToFloatCore(object obj, CultureInfo culture, out float value) - { - var text = (string)obj; - if (string.IsNullOrEmpty(text)) - { - value = default; - return false; - } - - if (!float.TryParse(text, NumberStyles.Number, culture ?? CultureInfo.CurrentCulture, out var converted)) - { - value = default; - return false; - } - - if (float.IsInfinity(converted) || float.IsNaN(converted)) - { - value = default; - return false; - } - - value = converted; - return true; - } - - private static bool ConvertToNullableFloatCore(object obj, CultureInfo culture, out float? value) - { - var text = (string)obj; - if (string.IsNullOrEmpty(text)) - { - value = default; - return true; - } - - if (!float.TryParse(text, NumberStyles.Number, culture ?? CultureInfo.CurrentCulture, out var converted)) - { - value = default; - return false; - } - - if (float.IsInfinity(converted) || float.IsNaN(converted)) - { - value = default; - return false; - } - - value = converted; - return true; - } - - /// - /// Attempts to convert a value to a . - /// - /// The object to convert. - /// The to use for conversion. - /// The converted value. - /// true if conversion is successful, otherwise false. - public static bool TryConvertToDouble(object obj, CultureInfo culture, out double value) - { - return ConvertToDoubleCore(obj, culture, out value); - } - - /// - /// Attempts to convert a value to a nullable . - /// - /// The object to convert. - /// The to use for conversion. - /// The converted value. - /// true if conversion is successful, otherwise false. - public static bool TryConvertToNullableDouble(object obj, CultureInfo culture, out double? value) - { - return ConvertToNullableDoubleCore(obj, culture, out value); - } - - internal static BindParser ConvertToDoubleDelegate = ConvertToDoubleCore; - internal static BindParser ConvertToNullableDoubleDelegate = ConvertToNullableDoubleCore; - - private static bool ConvertToDoubleCore(object obj, CultureInfo culture, out double value) - { - var text = (string)obj; - if (string.IsNullOrEmpty(text)) - { - value = default; - return false; - } - - if (!double.TryParse(text, NumberStyles.Number, culture ?? CultureInfo.CurrentCulture, out var converted)) - { - value = default; - return false; - } - - if (double.IsInfinity(converted) || double.IsNaN(converted)) - { - value = default; - return false; - } - - value = converted; - return true; - } - - private static bool ConvertToNullableDoubleCore(object obj, CultureInfo culture, out double? value) - { - var text = (string)obj; - if (string.IsNullOrEmpty(text)) - { - value = default; - return true; - } - - if (!double.TryParse(text, NumberStyles.Number, culture ?? CultureInfo.CurrentCulture, out var converted)) - { - value = default; - return false; - } - - if (double.IsInfinity(converted) || double.IsNaN(converted)) - { - value = default; - return false; - } - - value = converted; - return true; - } - - /// - /// Attempts to convert a value to a . - /// - /// The object to convert. - /// The to use for conversion. - /// The converted value. - /// true if conversion is successful, otherwise false. - public static bool TryConvertToDecimal(object obj, CultureInfo culture, out decimal value) - { - return ConvertToDecimalCore(obj, culture, out value); - } - - /// - /// Attempts to convert a value to a nullable . - /// - /// The object to convert. - /// The to use for conversion. - /// The converted value. - /// true if conversion is successful, otherwise false. - public static bool TryConvertToNullableDecimal(object obj, CultureInfo culture, out decimal? value) - { - return ConvertToNullableDecimalCore(obj, culture, out value); - } - - internal static BindParser ConvertToDecimal = ConvertToDecimalCore; - internal static BindParser ConvertToNullableDecimal = ConvertToNullableDecimalCore; - - private static bool ConvertToDecimalCore(object obj, CultureInfo culture, out decimal value) - { - var text = (string)obj; - if (string.IsNullOrEmpty(text)) - { - value = default; - return false; - } - - if (!decimal.TryParse(text, NumberStyles.Number, culture ?? CultureInfo.CurrentCulture, out var converted)) - { - value = default; - return false; - } - - value = converted; - return true; - } - - private static bool ConvertToNullableDecimalCore(object obj, CultureInfo culture, out decimal? value) - { - var text = (string)obj; - if (string.IsNullOrEmpty(text)) - { - value = default; - return true; - } - - if (!decimal.TryParse(text, NumberStyles.Number, culture ?? CultureInfo.CurrentCulture, out var converted)) - { - value = default; - return false; - } - - value = converted; - return true; - } - - /// - /// Attempts to convert a value to a . - /// - /// The object to convert. - /// The to use for conversion. - /// The converted value. - /// true if conversion is successful, otherwise false. - public static bool TryConvertToDateTime(object obj, CultureInfo culture, out DateTime value) - { - return ConvertToDateTimeCore(obj, culture, out value); - } - - /// - /// Attempts to convert a value to a . - /// - /// The object to convert. - /// The to use for conversion. - /// The format string to use in conversion. - /// The converted value. - /// true if conversion is successful, otherwise false. - public static bool TryConvertToDateTime(object obj, CultureInfo culture, string format, out DateTime value) - { - return ConvertToDateTimeCore(obj, culture, format, out value); - } - - /// - /// Attempts to convert a value to a nullable . - /// - /// The object to convert. - /// The to use for conversion. - /// The converted value. - /// true if conversion is successful, otherwise false. - public static bool TryConvertToNullableDateTime(object obj, CultureInfo culture, out DateTime? value) - { - return ConvertToNullableDateTimeCore(obj, culture, out value); - } - - /// - /// Attempts to convert a value to a nullable . - /// - /// The object to convert. - /// The to use for conversion. - /// The format string to use in conversion. - /// The converted value. - /// true if conversion is successful, otherwise false. - public static bool TryConvertToNullableDateTime(object obj, CultureInfo culture, string format, out DateTime? value) - { - return ConvertToNullableDateTimeCore(obj, culture, format, out value); - } - - internal static BindParser ConvertToDateTime = ConvertToDateTimeCore; - internal static BindParserWithFormat ConvertToDateTimeWithFormat = ConvertToDateTimeCore; - internal static BindParser ConvertToNullableDateTime = ConvertToNullableDateTimeCore; - internal static BindParserWithFormat ConvertToNullableDateTimeWithFormat = ConvertToNullableDateTimeCore; - - private static bool ConvertToDateTimeCore(object obj, CultureInfo culture, out DateTime value) - { - return ConvertToDateTimeCore(obj, culture, format: null, out value); - } - - private static bool ConvertToDateTimeCore(object obj, CultureInfo culture, string format, out DateTime value) - { - var text = (string)obj; - if (string.IsNullOrEmpty(text)) - { - value = default; - return false; - } - - if (format != null && DateTime.TryParseExact(text, format, culture ?? CultureInfo.CurrentCulture, DateTimeStyles.None, out var converted)) - { - value = converted; - return true; - } - else if (format == null && DateTime.TryParse(text, culture ?? CultureInfo.CurrentCulture, DateTimeStyles.None, out converted)) - { - value = converted; - return true; - } - - value = default; - return false; - } - - private static bool ConvertToNullableDateTimeCore(object obj, CultureInfo culture, out DateTime? value) - { - return ConvertToNullableDateTimeCore(obj, culture, format: null, out value); - } - - private static bool ConvertToNullableDateTimeCore(object obj, CultureInfo culture, string format, out DateTime? value) - { - var text = (string)obj; - if (string.IsNullOrEmpty(text)) - { - value = default; - return true; - } - - if (format != null && DateTime.TryParseExact(text, format, culture ?? CultureInfo.CurrentCulture, DateTimeStyles.None, out var converted)) - { - value = converted; - return true; - } - else if (format == null && DateTime.TryParse(text, culture ?? CultureInfo.CurrentCulture, DateTimeStyles.None, out converted)) - { - value = converted; - return true; - } - - value = default; - return false; - } - - /// - /// Attempts to convert a value to a . - /// - /// The object to convert. - /// The to use for conversion. - /// The converted value. - /// true if conversion is successful, otherwise false. - public static bool TryConvertToDateTimeOffset(object obj, CultureInfo culture, out DateTimeOffset value) - { - return ConvertToDateTimeOffsetCore(obj, culture, out value); - } - - /// - /// Attempts to convert a value to a . - /// - /// The object to convert. - /// The to use for conversion. - /// The format string to use in conversion. - /// The converted value. - /// true if conversion is successful, otherwise false. - public static bool TryConvertToDateTimeOffset(object obj, CultureInfo culture, string format, out DateTimeOffset value) - { - return ConvertToDateTimeOffsetCore(obj, culture, format, out value); - } - - /// - /// Attempts to convert a value to a nullable . - /// - /// The object to convert. - /// The to use for conversion. - /// The converted value. - /// true if conversion is successful, otherwise false. - public static bool TryConvertToNullableDateTimeOffset(object obj, CultureInfo culture, out DateTimeOffset? value) - { - return ConvertToNullableDateTimeOffsetCore(obj, culture, out value); - } - - /// - /// Attempts to convert a value to a nullable . - /// - /// The object to convert. - /// The to use for conversion. - /// The format string to use in conversion. - /// The converted value. - /// true if conversion is successful, otherwise false. - public static bool TryConvertToNullableDateTimeOffset(object obj, CultureInfo culture, string format, out DateTimeOffset? value) - { - return ConvertToNullableDateTimeOffsetCore(obj, culture, format, out value); - } - - internal static BindParser ConvertToDateTimeOffset = ConvertToDateTimeOffsetCore; - internal static BindParserWithFormat ConvertToDateTimeOffsetWithFormat = ConvertToDateTimeOffsetCore; - internal static BindParser ConvertToNullableDateTimeOffset = ConvertToNullableDateTimeOffsetCore; - internal static BindParserWithFormat ConvertToNullableDateTimeOffsetWithFormat = ConvertToNullableDateTimeOffsetCore; - - private static bool ConvertToDateTimeOffsetCore(object obj, CultureInfo culture, out DateTimeOffset value) - { - return ConvertToDateTimeOffsetCore(obj, culture, format: null, out value); - } - - private static bool ConvertToDateTimeOffsetCore(object obj, CultureInfo culture, string format, out DateTimeOffset value) - { - var text = (string)obj; - if (string.IsNullOrEmpty(text)) - { - value = default; - return false; - } - - if (format != null && DateTimeOffset.TryParseExact(text, format, culture ?? CultureInfo.CurrentCulture, DateTimeStyles.None, out var converted)) - { - value = converted; - return true; - } - else if (format == null && DateTimeOffset.TryParse(text, culture ?? CultureInfo.CurrentCulture, DateTimeStyles.None, out converted)) - { - value = converted; - return true; - } - - value = default; - return false; - } - - private static bool ConvertToNullableDateTimeOffsetCore(object obj, CultureInfo culture, out DateTimeOffset? value) - { - return ConvertToNullableDateTimeOffsetCore(obj, culture, format: null, out value); - } - - private static bool ConvertToNullableDateTimeOffsetCore(object obj, CultureInfo culture, string format, out DateTimeOffset? value) - { - var text = (string)obj; - if (string.IsNullOrEmpty(text)) - { - value = default; - return true; - } - - if (format != null && DateTimeOffset.TryParseExact(text, format, culture ?? CultureInfo.CurrentCulture, DateTimeStyles.None, out var converted)) - { - value = converted; - return true; - } - else if (format == null && DateTimeOffset.TryParse(text, culture ?? CultureInfo.CurrentCulture, DateTimeStyles.None, out converted)) - { - value = converted; - return true; - } - - value = default; - return false; - } - - private static bool ConvertToEnum(object obj, CultureInfo culture, out T value) where T : struct, Enum - { - var text = (string)obj; - if (string.IsNullOrEmpty(text)) - { - value = default; - return true; - } - - if (!Enum.TryParse(text, out var converted)) - { - value = default; - return false; - } - - if (!Enum.IsDefined(typeof(T), converted)) - { - value = default; - return false; - } - - value = converted; - return true; - } - - private static bool ConvertToNullableEnum(object obj, CultureInfo culture, out T? value) where T : struct, Enum - { - var text = (string)obj; - if (string.IsNullOrEmpty(text)) - { - value = default; - return true; - } - - if (!Enum.TryParse(text, out var converted)) - { - value = default; - return false; - } - - if (!Enum.IsDefined(typeof(T), converted)) - { - value = default; - return false; - } - - value = converted; - return true; - } - - /// - /// Attempts to convert a value to a value of type . - /// - /// The object to convert. - /// The to use for conversion. - /// The converted value. - /// true if conversion is successful, otherwise false. - public static bool TryConvertTo(object obj, CultureInfo culture, out T value) - { - var converter = ParserDelegateCache.Get(); - return converter(obj, culture, out value); - } - - private static class FormatterDelegateCache - { - private readonly static ConcurrentDictionary _cache = new ConcurrentDictionary(); - - private static MethodInfo _formatEnumValue; - private static MethodInfo _formatNullableEnumValue; - - public static BindFormatter Get() - { - if (!_cache.TryGetValue(typeof(T), out var formattter)) - { - // We need to replicate all of the primitive cases that we handle here so that they will behave the same way. - // The result will be cached. - if (typeof(T) == typeof(string)) - { - formattter = (BindFormatter)FormatStringValueCore; - } - else if (typeof(T) == typeof(bool)) - { - formattter = (BindFormatter)FormatBoolValueCore; - } - else if (typeof(T) == typeof(bool?)) - { - formattter = (BindFormatter)FormatNullableBoolValueCore; - } - else if (typeof(T) == typeof(int)) - { - formattter = (BindFormatter)FormatIntValueCore; - } - else if (typeof(T) == typeof(int?)) - { - formattter = (BindFormatter)FormatNullableIntValueCore; - } - else if (typeof(T) == typeof(long)) - { - formattter = (BindFormatter)FormatLongValueCore; - } - else if (typeof(T) == typeof(long?)) - { - formattter = (BindFormatter)FormatNullableLongValueCore; - } - else if (typeof(T) == typeof(float)) - { - formattter = (BindFormatter)FormatFloatValueCore; - } - else if (typeof(T) == typeof(float?)) - { - formattter = (BindFormatter)FormatNullableFloatValueCore; - } - else if (typeof(T) == typeof(double)) - { - formattter = (BindFormatter)FormatDoubleValueCore; - } - else if (typeof(T) == typeof(double?)) - { - formattter = (BindFormatter)FormatNullableDoubleValueCore; - } - else if (typeof(T) == typeof(decimal)) - { - formattter = (BindFormatter)FormatDecimalValueCore; - } - else if (typeof(T) == typeof(decimal?)) - { - formattter = (BindFormatter)FormatNullableDecimalValueCore; - } - else if (typeof(T) == typeof(DateTime)) - { - formattter = (BindFormatter)FormatDateTimeValueCore; - } - else if (typeof(T) == typeof(DateTime?)) - { - formattter = (BindFormatter)FormatNullableDateTimeValueCore; - } - else if (typeof(T) == typeof(DateTimeOffset)) - { - formattter = (BindFormatter)FormatDateTimeOffsetValueCore; - } - else if (typeof(T) == typeof(DateTimeOffset?)) - { - formattter = (BindFormatter)FormatNullableDateTimeOffsetValueCore; - } - else if (typeof(T).IsEnum) - { - // We have to deal invoke this dynamically to work around the type constraint on Enum.TryParse. - var method = _formatEnumValue ??= typeof(BindConverter).GetMethod(nameof(FormatEnumValueCore), BindingFlags.NonPublic | BindingFlags.Static); - formattter = method.MakeGenericMethod(typeof(T)).CreateDelegate(typeof(BindFormatter), target: null); - } - else if (Nullable.GetUnderlyingType(typeof(T)) is Type innerType && innerType.IsEnum) - { - // We have to deal invoke this dynamically to work around the type constraint on Enum.TryParse. - var method = _formatNullableEnumValue ??= typeof(BindConverter).GetMethod(nameof(FormatNullableEnumValueCore), BindingFlags.NonPublic | BindingFlags.Static); - formattter = method.MakeGenericMethod(innerType).CreateDelegate(typeof(BindFormatter), target: null); - } - else - { - formattter = MakeTypeConverterFormatter(); - } - - _cache.TryAdd(typeof(T), formattter); - } - - return (BindFormatter)formattter; - } - - private static BindFormatter MakeTypeConverterFormatter() - { - var typeConverter = TypeDescriptor.GetConverter(typeof(T)); - if (typeConverter == null || !typeConverter.CanConvertTo(typeof(string))) - { - throw new InvalidOperationException( - $"The type '{typeof(T).FullName}' does not have an associated {typeof(TypeConverter).Name} that supports " + - $"conversion to a string. " + - $"Apply '{typeof(TypeConverterAttribute).Name}' to the type to register a converter."); - } - - return FormatWithTypeConverter; - - string FormatWithTypeConverter(T value, CultureInfo culture) - { - // We intentionally close-over the TypeConverter to cache it. The TypeDescriptor infrastructure is slow. - return typeConverter.ConvertToString(context: null, culture ?? CultureInfo.CurrentCulture, value); - } - } - } - - internal static class ParserDelegateCache - { - private readonly static ConcurrentDictionary _cache = new ConcurrentDictionary(); - - private static MethodInfo _convertToEnum; - private static MethodInfo _convertToNullableEnum; - - public static BindParser Get() - { - if (!_cache.TryGetValue(typeof(T), out var parser)) - { - // We need to replicate all of the primitive cases that we handle here so that they will behave the same way. - // The result will be cached. - if (typeof(T) == typeof(string)) - { - parser = ConvertToString; - } - else if (typeof(T) == typeof(bool)) - { - parser = ConvertToBool; - } - else if (typeof(T) == typeof(bool?)) - { - parser = ConvertToNullableBool; - } - else if (typeof(T) == typeof(int)) - { - parser = ConvertToInt; - } - else if (typeof(T) == typeof(int?)) - { - parser = ConvertToNullableInt; - } - else if (typeof(T) == typeof(long)) - { - parser = ConvertToLong; - } - else if (typeof(T) == typeof(long?)) - { - parser = ConvertToNullableLong; - } - else if (typeof(T) == typeof(float)) - { - parser = ConvertToFloat; - } - else if (typeof(T) == typeof(float?)) - { - parser = ConvertToNullableFloat; - } - else if (typeof(T) == typeof(double)) - { - parser = ConvertToDoubleDelegate; - } - else if (typeof(T) == typeof(double?)) - { - parser = ConvertToNullableDoubleDelegate; - } - else if (typeof(T) == typeof(decimal)) - { - parser = ConvertToDecimal; - } - else if (typeof(T) == typeof(decimal?)) - { - parser = ConvertToNullableDecimal; - } - else if (typeof(T) == typeof(DateTime)) - { - parser = ConvertToDateTime; - } - else if (typeof(T) == typeof(DateTime?)) - { - parser = ConvertToNullableDateTime; - } - else if (typeof(T) == typeof(DateTimeOffset)) - { - parser = ConvertToDateTime; - } - else if (typeof(T) == typeof(DateTimeOffset?)) - { - parser = ConvertToNullableDateTime; - } - else if (typeof(T).IsEnum) - { - // We have to deal invoke this dynamically to work around the type constraint on Enum.TryParse. - var method = _convertToEnum ??= typeof(BindConverter).GetMethod(nameof(ConvertToEnum), BindingFlags.NonPublic | BindingFlags.Static); - parser = method.MakeGenericMethod(typeof(T)).CreateDelegate(typeof(BindParser), target: null); - } - else if (Nullable.GetUnderlyingType(typeof(T)) is Type innerType && innerType.IsEnum) - { - // We have to deal invoke this dynamically to work around the type constraint on Enum.TryParse. - var method = _convertToNullableEnum ??= typeof(BindConverter).GetMethod(nameof(ConvertToNullableEnum), BindingFlags.NonPublic | BindingFlags.Static); - parser = method.MakeGenericMethod(innerType).CreateDelegate(typeof(BindParser), target: null); - } - else - { - parser = MakeTypeConverterConverter(); - } - - _cache.TryAdd(typeof(T), parser); - } - - return (BindParser)parser; - } - - private static BindParser MakeTypeConverterConverter() - { - var typeConverter = TypeDescriptor.GetConverter(typeof(T)); - if (typeConverter == null || !typeConverter.CanConvertFrom(typeof(string))) - { - throw new InvalidOperationException( - $"The type '{typeof(T).FullName}' does not have an associated {typeof(TypeConverter).Name} that supports " + - $"conversion from a string. " + - $"Apply '{typeof(TypeConverterAttribute).Name}' to the type to register a converter."); - } - - return ConvertWithTypeConverter; - - bool ConvertWithTypeConverter(object obj, CultureInfo culture, out T value) - { - // We intentionally close-over the TypeConverter to cache it. The TypeDescriptor infrastructure is slow. - var converted = typeConverter.ConvertFrom(context: null, culture ?? CultureInfo.CurrentCulture, obj); - if (converted == null) - { - value = default; - return true; - } - - value = (T)converted; - return true; - } - } - } - } -} diff --git a/src/Components/Components/src/BindElementAttribute.cs b/src/Components/Components/src/BindElementAttribute.cs deleted file mode 100644 index ffc17a6049..0000000000 --- a/src/Components/Components/src/BindElementAttribute.cs +++ /dev/null @@ -1,64 +0,0 @@ -// 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.AspNetCore.Components -{ - /// - /// Configures options for binding specific element types. - /// - [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)] - public sealed class BindElementAttribute : Attribute - { - /// - /// Constructs an instance of . - /// - /// The tag name of the element. - /// The suffix value. For example, set this to value for bind-value, or set this to null for bind. - /// The name of the value attribute to be bound. - /// The name of an attribute that will register an associated change event. - public BindElementAttribute(string element, string suffix, string valueAttribute, string changeAttribute) - { - if (element == null) - { - throw new ArgumentNullException(nameof(element)); - } - - if (valueAttribute == null) - { - throw new ArgumentNullException(nameof(valueAttribute)); - } - - if (changeAttribute == null) - { - throw new ArgumentNullException(nameof(changeAttribute)); - } - - Element = element; - ValueAttribute = valueAttribute; - ChangeAttribute = changeAttribute; - } - - /// - /// Gets the tag name of the element. - /// - public string Element { get; } - - /// - /// Gets the suffix value. - /// For example, this will be value to mean bind-value, or null to mean bind. - /// - public string Suffix { get; } - - /// - /// Gets the name of the value attribute to be bound. - /// - public string ValueAttribute { get; } - - /// - /// Gets the name of an attribute that will register an associated change event. - /// - public string ChangeAttribute { get; } - } -} diff --git a/src/Components/Components/src/CascadingParameterAttribute.cs b/src/Components/Components/src/CascadingParameterAttribute.cs deleted file mode 100644 index ca8113976b..0000000000 --- a/src/Components/Components/src/CascadingParameterAttribute.cs +++ /dev/null @@ -1,27 +0,0 @@ -// 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.AspNetCore.Components -{ - /// - /// Denotes the target member as a cascading component parameter. Its value will be - /// supplied by the closest ancestor component that - /// supplies values with a compatible type and name. - /// - [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)] - public sealed class CascadingParameterAttribute : Attribute - { - /// - /// If specified, the parameter value will be supplied by the closest - /// ancestor that supplies a value with - /// this name. - /// - /// If null, the parameter value will be supplied by the closest ancestor - /// that supplies a value with a compatible - /// type. - /// - public string Name { get; set; } - } -} diff --git a/src/Components/Components/src/CascadingParameterState.cs b/src/Components/Components/src/CascadingParameterState.cs deleted file mode 100644 index 8c3e445a86..0000000000 --- a/src/Components/Components/src/CascadingParameterState.cs +++ /dev/null @@ -1,129 +0,0 @@ -// 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.AspNetCore.Components.Reflection; -using Microsoft.AspNetCore.Components.Rendering; -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Reflection; - -namespace Microsoft.AspNetCore.Components -{ - internal readonly struct CascadingParameterState - { - private readonly static ConcurrentDictionary _cachedInfos - = new ConcurrentDictionary(); - - public string LocalValueName { get; } - public ICascadingValueComponent ValueSupplier { get; } - - public CascadingParameterState(string localValueName, ICascadingValueComponent valueSupplier) - { - LocalValueName = localValueName; - ValueSupplier = valueSupplier; - } - - public static IReadOnlyList FindCascadingParameters(ComponentState componentState) - { - var componentType = componentState.Component.GetType(); - var infos = GetReflectedCascadingParameterInfos(componentType); - - // For components known not to have any cascading parameters, bail out early - if (infos == null) - { - return null; - } - - // Now try to find matches for each of the cascading parameters - // Defer instantiation of the result list until we know there's at least one - List resultStates = null; - - var numInfos = infos.Length; - for (var infoIndex = 0; infoIndex < numInfos; infoIndex++) - { - ref var info = ref infos[infoIndex]; - var supplier = GetMatchingCascadingValueSupplier(info, componentState); - if (supplier != null) - { - if (resultStates == null) - { - // Although not all parameters might be matched, we know the maximum number - resultStates = new List(infos.Length - infoIndex); - } - - resultStates.Add(new CascadingParameterState(info.ConsumerValueName, supplier)); - } - } - - return resultStates; - } - - private static ICascadingValueComponent GetMatchingCascadingValueSupplier(in ReflectedCascadingParameterInfo info, ComponentState componentState) - { - do - { - if (componentState.Component is ICascadingValueComponent candidateSupplier - && candidateSupplier.CanSupplyValue(info.ValueType, info.SupplierValueName)) - { - return candidateSupplier; - } - - componentState = componentState.ParentComponentState; - } while (componentState != null); - - // No match - return null; - } - - private static ReflectedCascadingParameterInfo[] GetReflectedCascadingParameterInfos(Type componentType) - { - if (!_cachedInfos.TryGetValue(componentType, out var infos)) - { - infos = CreateReflectedCascadingParameterInfos(componentType); - _cachedInfos[componentType] = infos; - } - - return infos; - } - - private static ReflectedCascadingParameterInfo[] CreateReflectedCascadingParameterInfos(Type componentType) - { - List result = null; - var candidateProps = ComponentProperties.GetCandidateBindableProperties(componentType); - foreach (var prop in candidateProps) - { - var attribute = prop.GetCustomAttribute(); - if (attribute != null) - { - if (result == null) - { - result = new List(); - } - - result.Add(new ReflectedCascadingParameterInfo( - prop.Name, - prop.PropertyType, - attribute.Name)); - } - } - - return result?.ToArray(); - } - - readonly struct ReflectedCascadingParameterInfo - { - public string ConsumerValueName { get; } - public string SupplierValueName { get; } - public Type ValueType { get; } - - public ReflectedCascadingParameterInfo( - string consumerValueName, Type valueType, string supplierValueName) - { - ConsumerValueName = consumerValueName; - SupplierValueName = supplierValueName; - ValueType = valueType; - } - } - } -} diff --git a/src/Components/Components/src/CascadingValue.cs b/src/Components/Components/src/CascadingValue.cs deleted file mode 100644 index db03b3d416..0000000000 --- a/src/Components/Components/src/CascadingValue.cs +++ /dev/null @@ -1,184 +0,0 @@ -// 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.Collections.Generic; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Components.Rendering; - -namespace Microsoft.AspNetCore.Components -{ - /// - /// A component that provides a cascading value to all descendant components. - /// - public class CascadingValue : ICascadingValueComponent, IComponent - { - private RenderHandle _renderHandle; - private HashSet _subscribers; // Lazily instantiated - private bool _hasSetParametersPreviously; - - /// - /// The content to which the value should be provided. - /// - [Parameter] public RenderFragment ChildContent { get; set; } - - /// - /// The value to be provided. - /// - [Parameter] public TValue Value { get; set; } - - /// - /// Optionally gives a name to the provided value. Descendant components - /// will be able to receive the value by specifying this name. - /// - /// If no name is specified, then descendant components will receive the - /// value based the type of value they are requesting. - /// - [Parameter] public string Name { get; set; } - - /// - /// If true, indicates that will not change. This is a - /// performance optimization that allows the framework to skip setting up - /// change notifications. Set this flag only if you will not change - /// during the component's lifetime. - /// - [Parameter] public bool IsFixed { get; set; } - - object ICascadingValueComponent.CurrentValue => Value; - - bool ICascadingValueComponent.CurrentValueIsFixed => IsFixed; - - /// - public void Attach(RenderHandle renderHandle) - { - _renderHandle = renderHandle; - } - - /// - public Task SetParametersAsync(ParameterView parameters) - { - // Implementing the parameter binding manually, instead of just calling - // parameters.SetParameterProperties(this), is just a very slight perf optimization - // and makes it simpler impose rules about the params being required or not. - - var hasSuppliedValue = false; - var previousValue = Value; - var previousFixed = IsFixed; - Value = default; - ChildContent = null; - Name = null; - IsFixed = false; - - foreach (var parameter in parameters) - { - if (parameter.Name.Equals(nameof(Value), StringComparison.OrdinalIgnoreCase)) - { - Value = (TValue)parameter.Value; - hasSuppliedValue = true; - } - else if (parameter.Name.Equals(nameof(ChildContent), StringComparison.OrdinalIgnoreCase)) - { - ChildContent = (RenderFragment)parameter.Value; - } - else if (parameter.Name.Equals(nameof(Name), StringComparison.OrdinalIgnoreCase)) - { - Name = (string)parameter.Value; - if (string.IsNullOrEmpty(Name)) - { - throw new ArgumentException($"The parameter '{nameof(Name)}' for component '{nameof(CascadingValue)}' does not allow null or empty values."); - } - } - else if (parameter.Name.Equals(nameof(IsFixed), StringComparison.OrdinalIgnoreCase)) - { - IsFixed = (bool)parameter.Value; - } - else - { - throw new ArgumentException($"The component '{nameof(CascadingValue)}' does not accept a parameter with the name '{parameter.Name}'."); - } - } - - if (_hasSetParametersPreviously && IsFixed != previousFixed) - { - throw new InvalidOperationException($"The value of {nameof(IsFixed)} cannot be changed dynamically."); - } - - _hasSetParametersPreviously = true; - - // It's OK for the value to be null, but some "Value" param must be suppled - // because it serves no useful purpose to have a otherwise. - if (!hasSuppliedValue) - { - throw new ArgumentException($"Missing required parameter '{nameof(Value)}' for component '{GetType().Name}'."); - } - - // Rendering is most efficient when things are queued from rootmost to leafmost. - // Given a components A (parent) -> B (child), you want them to be queued in order - // [A, B] because if you had [B, A], then the render for A might change B's params - // making it render again, so you'd render [B, A, B], which is wasteful. - // At some point we might consider making the render queue actually enforce this - // ordering during insertion. - // - // For the CascadingValue component, this observation is why it's important to render - // ourself before notifying subscribers (which can be grandchildren or deeper). - // If we rerendered subscribers first, then our own subsequent render might cause an - // further update that makes those nested subscribers get rendered twice. - _renderHandle.Render(Render); - - if (_subscribers != null && ChangeDetection.MayHaveChanged(previousValue, Value)) - { - NotifySubscribers(parameters.Lifetime); - } - - return Task.CompletedTask; - } - - bool ICascadingValueComponent.CanSupplyValue(Type requestedType, string requestedName) - { - if (!requestedType.IsAssignableFrom(typeof(TValue))) - { - return false; - } - - return (requestedName == null && Name == null) // Match on type alone - || string.Equals(requestedName, Name, StringComparison.OrdinalIgnoreCase); // Also match on name - } - - void ICascadingValueComponent.Subscribe(ComponentState subscriber) - { -#if DEBUG - if (IsFixed) - { - // Should not be possible. User code cannot trigger this. - // Checking only to catch possible future framework bugs. - throw new InvalidOperationException($"Cannot subscribe to a {typeof(CascadingValue<>).Name} when {nameof(IsFixed)} is true."); - } -#endif - - if (_subscribers == null) - { - _subscribers = new HashSet(); - } - - _subscribers.Add(subscriber); - } - - void ICascadingValueComponent.Unsubscribe(ComponentState subscriber) - { - _subscribers.Remove(subscriber); - } - - private void NotifySubscribers(in ParameterViewLifetime lifetime) - { - foreach (var subscriber in _subscribers) - { - subscriber.NotifyCascadingValueChanged(lifetime); - } - } - - private void Render(RenderTreeBuilder builder) - { - builder.AddContent(0, ChildContent); - } - } -} diff --git a/src/Components/Components/src/ChangeDetection.cs b/src/Components/Components/src/ChangeDetection.cs deleted file mode 100644 index 9a0a1620be..0000000000 --- a/src/Components/Components/src/ChangeDetection.cs +++ /dev/null @@ -1,46 +0,0 @@ -// 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.AspNetCore.Components -{ - internal class ChangeDetection - { - public static bool MayHaveChanged(T1 oldValue, T2 newValue) - { - var oldIsNotNull = oldValue != null; - var newIsNotNull = newValue != null; - if (oldIsNotNull != newIsNotNull) - { - return true; // One's null and the other isn't, so different - } - else if (oldIsNotNull) // i.e., both are not null (considering previous check) - { - var oldValueType = oldValue.GetType(); - var newValueType = newValue.GetType(); - if (oldValueType != newValueType // Definitely different - || !IsKnownImmutableType(oldValueType) // Maybe different - || !oldValue.Equals(newValue)) // Somebody says they are different - { - return true; - } - } - - // By now we know either both are null, or they are the same immutable type - // and ThatType::Equals says the two values are equal. - return false; - } - - // The contents of this list need to trade off false negatives against computation - // time. So we don't want a huge list of types to check (or would have to move to - // a hashtable lookup, which is differently expensive). It's better not to include - // uncommon types here even if they are known to be immutable. - private static bool IsKnownImmutableType(Type type) - => type.IsPrimitive - || type == typeof(string) - || type == typeof(DateTime) - || type == typeof(Type) - || type == typeof(decimal); - } -} diff --git a/src/Components/Components/src/ChangeEventArgs.cs b/src/Components/Components/src/ChangeEventArgs.cs deleted file mode 100644 index e64e4c10c7..0000000000 --- a/src/Components/Components/src/ChangeEventArgs.cs +++ /dev/null @@ -1,19 +0,0 @@ -// 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.AspNetCore.Components -{ - /// - /// Supplies information about an change event that is being raised. - /// - public class ChangeEventArgs : EventArgs - { - /// - /// Gets or sets the new value. - /// - public object Value { get; set; } - - } -} diff --git a/src/Components/Components/src/CompilerServices/RuntimeHelpers.cs b/src/Components/Components/src/CompilerServices/RuntimeHelpers.cs deleted file mode 100644 index 5d3469e622..0000000000 --- a/src/Components/Components/src/CompilerServices/RuntimeHelpers.cs +++ /dev/null @@ -1,56 +0,0 @@ -// 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; - -namespace Microsoft.AspNetCore.Components.CompilerServices -{ - /// - /// Used by generated code produced by the Components code generator. Not intended or supported - /// for use in application code. - /// - public static class RuntimeHelpers - { - /// - /// Not intended for use by application code. - /// - /// - /// - /// - public static T TypeCheck(T value) => value; - - /// - /// Not intended for use by application code. - /// - /// - /// - /// - /// - // - // This method is used with `@bind-Value` for components. When a component has a generic type, it's - // really messy to write to try and write the parameter type for ValueChanged - because it can contain generic - // type parameters. We're using a trick of type inference to generate the proper typing for the delegate - // so that method-group-to-delegate conversion works. - public static EventCallback CreateInferredEventCallback(object receiver, Action callback, T value) - { - return EventCallback.Factory.Create(receiver, callback); - } - - /// - /// Not intended for use by application code. - /// - /// - /// - /// - /// - // - // This method is used with `@bind-Value` for components. When a component has a generic type, it's - // really messy to write to try and write the parameter type for ValueChanged - because it can contain generic - // type parameters. We're using a trick of type inference to generate the proper typing for the delegate - // so that method-group-to-delegate conversion works. - public static EventCallback CreateInferredEventCallback(object receiver, Func callback, T value) - { - return EventCallback.Factory.Create(receiver, callback); - } - } -} diff --git a/src/Components/Components/src/ComponentBase.cs b/src/Components/Components/src/ComponentBase.cs deleted file mode 100644 index 51c95f386b..0000000000 --- a/src/Components/Components/src/ComponentBase.cs +++ /dev/null @@ -1,336 +0,0 @@ -// 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.Rendering; - -namespace Microsoft.AspNetCore.Components -{ - // IMPORTANT - // - // Many of these names are used in code generation. Keep these in sync with the code generation code - // See: src/Microsoft.AspNetCore.Components.Razor.Extensions/ComponentsApi.cs - - // Most of the developer-facing component lifecycle concepts are encapsulated in this - // base class. The core components rendering system doesn't know about them (it only knows - // about IComponent). This gives us flexibility to change the lifecycle concepts easily, - // or for developers to design their own lifecycles as different base classes. - - // TODO: When the component lifecycle design stabilises, add proper unit tests for ComponentBase. - - /// - /// Optional base class for components. Alternatively, components may - /// implement directly. - /// - public abstract class ComponentBase : IComponent, IHandleEvent, IHandleAfterRender - { - private readonly RenderFragment _renderFragment; - private RenderHandle _renderHandle; - private bool _initialized; - private bool _hasNeverRendered = true; - private bool _hasPendingQueuedRender; - private bool _hasCalledOnAfterRender; - - /// - /// Constructs an instance of . - /// - public ComponentBase() - { - _renderFragment = builder => - { - _hasPendingQueuedRender = false; - _hasNeverRendered = false; - BuildRenderTree(builder); - }; - } - - /// - /// Renders the component to the supplied . - /// - /// A that will receive the render output. - protected virtual void BuildRenderTree(RenderTreeBuilder builder) - { - // Developers can either override this method in derived classes, or can use Razor - // syntax to define a derived class and have the compiler generate the method. - - // Other code within this class should *not* invoke BuildRenderTree directly, - // but instead should invoke the _renderFragment field. - } - - /// - /// Method invoked when the component is ready to start, having received its - /// initial parameters from its parent in the render tree. - /// - protected virtual void OnInitialized() - { - } - - /// - /// Method invoked when the component is ready to start, having received its - /// initial parameters from its parent in the render tree. - /// - /// Override this method if you will perform an asynchronous operation and - /// want the component to refresh when that operation is completed. - /// - /// A representing any asynchronous operation. - protected virtual Task OnInitializedAsync() - => Task.CompletedTask; - - /// - /// Method invoked when the component has received parameters from its parent in - /// the render tree, and the incoming values have been assigned to properties. - /// - protected virtual void OnParametersSet() - { - } - - /// - /// Method invoked when the component has received parameters from its parent in - /// the render tree, and the incoming values have been assigned to properties. - /// - /// A representing any asynchronous operation. - protected virtual Task OnParametersSetAsync() - => Task.CompletedTask; - - /// - /// Notifies the component that its state has changed. When applicable, this will - /// cause the component to be re-rendered. - /// - protected void StateHasChanged() - { - if (_hasPendingQueuedRender) - { - return; - } - - if (_hasNeverRendered || ShouldRender()) - { - _hasPendingQueuedRender = true; - - try - { - _renderHandle.Render(_renderFragment); - } - catch - { - _hasPendingQueuedRender = false; - throw; - } - } - } - - /// - /// Returns a flag to indicate whether the component should render. - /// - /// - protected virtual bool ShouldRender() - => true; - - /// - /// Method invoked after each time the component has been rendered. - /// - /// - /// Set to true if this is the first time has been invoked - /// on this component instance; otherwise false. - /// - /// - /// The and lifecycle methods - /// are useful for performing interop, or interacting with values recieved from @ref. - /// Use the parameter to ensure that initialization work is only performed - /// once. - /// - protected virtual void OnAfterRender(bool firstRender) - { - } - - /// - /// Method invoked after each time the component has been rendered. Note that the component does - /// not automatically re-render after the completion of any returned , because - /// that would cause an infinite render loop. - /// - /// - /// Set to true if this is the first time has been invoked - /// on this component instance; otherwise false. - /// - /// A representing any asynchronous operation. - /// - /// The and lifecycle methods - /// are useful for performing interop, or interacting with values recieved from @ref. - /// Use the parameter to ensure that initialization work is only performed - /// once. - /// - protected virtual Task OnAfterRenderAsync(bool firstRender) - => Task.CompletedTask; - - /// - /// Executes the supplied work item on the associated renderer's - /// synchronization context. - /// - /// The work item to execute. - protected Task InvokeAsync(Action workItem) - => _renderHandle.Dispatcher.InvokeAsync(workItem); - - /// - /// Executes the supplied work item on the associated renderer's - /// synchronization context. - /// - /// The work item to execute. - protected Task InvokeAsync(Func workItem) - => _renderHandle.Dispatcher.InvokeAsync(workItem); - - void IComponent.Attach(RenderHandle renderHandle) - { - // This implicitly means a ComponentBase can only be associated with a single - // renderer. That's the only use case we have right now. If there was ever a need, - // a component could hold a collection of render handles. - if (_renderHandle.IsInitialized) - { - throw new InvalidOperationException($"The render handle is already set. Cannot initialize a {nameof(ComponentBase)} more than once."); - } - - _renderHandle = renderHandle; - } - - - /// - /// Sets parameters supplied by the component's parent in the render tree. - /// - /// The parameters. - /// A that completes when the component has finished updating and rendering itself. - /// - /// - /// The method should be passed the entire set of parameter values each - /// time is called. It not required that the caller supply a parameter - /// value for all parameters that are logically understood by the component. - /// - /// - /// The default implementation of will set the value of each property - /// decorated with or that has - /// a corresponding value in the . Parameters that do not have a corresponding value - /// will be unchanged. - /// - /// - public virtual Task SetParametersAsync(ParameterView parameters) - { - parameters.SetParameterProperties(this); - if (!_initialized) - { - _initialized = true; - - return RunInitAndSetParametersAsync(); - } - else - { - return CallOnParametersSetAsync(); - } - } - - private async Task RunInitAndSetParametersAsync() - { - OnInitialized(); - var task = OnInitializedAsync(); - - if (task.Status != TaskStatus.RanToCompletion && task.Status != TaskStatus.Canceled) - { - // Call state has changed here so that we render after the sync part of OnInitAsync has run - // and wait for it to finish before we continue. If no async work has been done yet, we want - // to defer calling StateHasChanged up until the first bit of async code happens or until - // the end. Additionally, we want to avoid calling StateHasChanged if no - // async work is to be performed. - StateHasChanged(); - - try - { - await task; - } - catch // avoiding exception filters for AOT runtime support - { - // Ignore exceptions from task cancelletions. - // Awaiting a canceled task may produce either an OperationCanceledException (if produced as a consequence of - // CancellationToken.ThrowIfCancellationRequested()) or a TaskCanceledException (produced as a consequence of awaiting Task.FromCanceled). - // It's much easier to check the state of the Task (i.e. Task.IsCanceled) rather than catch two distinct exceptions. - if (!task.IsCanceled) - { - throw; - } - } - - // Don't call StateHasChanged here. CallOnParametersSetAsync should handle that for us. - } - - await CallOnParametersSetAsync(); - } - - private Task CallOnParametersSetAsync() - { - OnParametersSet(); - var task = OnParametersSetAsync(); - // If no async work is to be performed, i.e. the task has already ran to completion - // or was canceled by the time we got to inspect it, avoid going async and re-invoking - // StateHasChanged at the culmination of the async work. - var shouldAwaitTask = task.Status != TaskStatus.RanToCompletion && - task.Status != TaskStatus.Canceled; - - // We always call StateHasChanged here as we want to trigger a rerender after OnParametersSet and - // the synchronous part of OnParametersSetAsync has run. - StateHasChanged(); - - return shouldAwaitTask ? - CallStateHasChangedOnAsyncCompletion(task) : - Task.CompletedTask; - } - - private async Task CallStateHasChangedOnAsyncCompletion(Task task) - { - try - { - await task; - } - catch // avoiding exception filters for AOT runtime support - { - // Ignore exceptions from task cancelletions, but don't bother issuing a state change. - if (task.IsCanceled) - { - return; - } - - throw; - } - - StateHasChanged(); - } - - Task IHandleEvent.HandleEventAsync(EventCallbackWorkItem callback, object arg) - { - var task = callback.InvokeAsync(arg); - var shouldAwaitTask = task.Status != TaskStatus.RanToCompletion && - task.Status != TaskStatus.Canceled; - - // After each event, we synchronously re-render (unless !ShouldRender()) - // This just saves the developer the trouble of putting "StateHasChanged();" - // at the end of every event callback. - StateHasChanged(); - - return shouldAwaitTask ? - CallStateHasChangedOnAsyncCompletion(task) : - Task.CompletedTask; - } - - Task IHandleAfterRender.OnAfterRenderAsync() - { - var firstRender = !_hasCalledOnAfterRender; - _hasCalledOnAfterRender |= true; - - OnAfterRender(firstRender); - - return OnAfterRenderAsync(firstRender); - - // Note that we don't call StateHasChanged to trigger a render after - // handling this, because that would be an infinite loop. The only - // reason we have OnAfterRenderAsync is so that the developer doesn't - // have to use "async void" and do their own exception handling in - // the case where they want to start an async task. - } - } -} diff --git a/src/Components/Components/src/ComponentFactory.cs b/src/Components/Components/src/ComponentFactory.cs deleted file mode 100644 index bf5de30d2a..0000000000 --- a/src/Components/Components/src/ComponentFactory.cs +++ /dev/null @@ -1,88 +0,0 @@ -// 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.Collections.Concurrent; -using System.Linq; -using System.Reflection; -using Microsoft.AspNetCore.Components.Reflection; - -namespace Microsoft.AspNetCore.Components -{ - /// - /// The property on this type is used as a static global cache. Ensure any changes to this type - /// are thread safe and can be safely cached statically. - /// - internal class ComponentFactory - { - private static readonly BindingFlags _injectablePropertyBindingFlags - = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; - - private readonly ConcurrentDictionary> _cachedInitializers - = new ConcurrentDictionary>(); - - public static readonly ComponentFactory Instance = new ComponentFactory(); - - public IComponent InstantiateComponent(IServiceProvider serviceProvider, Type componentType) - { - var instance = Activator.CreateInstance(componentType); - if (!(instance is IComponent component)) - { - throw new ArgumentException($"The type {componentType.FullName} does not implement {nameof(IComponent)}.", nameof(componentType)); - } - - PerformPropertyInjection(serviceProvider, component); - return component; - } - - private void PerformPropertyInjection(IServiceProvider serviceProvider, IComponent instance) - { - // This is thread-safe because _cachedInitializers is a ConcurrentDictionary. - // We might generate the initializer more than once for a given type, but would - // still produce the correct result. - var instanceType = instance.GetType(); - if (!_cachedInitializers.TryGetValue(instanceType, out var initializer)) - { - initializer = CreateInitializer(instanceType); - _cachedInitializers.TryAdd(instanceType, initializer); - } - - initializer(serviceProvider, instance); - } - - private Action CreateInitializer(Type type) - { - // Do all the reflection up front - var injectableProperties = - MemberAssignment.GetPropertiesIncludingInherited(type, _injectablePropertyBindingFlags) - .Where(p => p.IsDefined(typeof(InjectAttribute))); - - var injectables = injectableProperties.Select(property => - ( - propertyName: property.Name, - propertyType: property.PropertyType, - setter: MemberAssignment.CreatePropertySetter(type, property, cascading: false) - )).ToArray(); - - return Initialize; - - // Return an action whose closure can write all the injected properties - // without any further reflection calls (just typecasts) - void Initialize(IServiceProvider serviceProvider, IComponent component) - { - foreach (var (propertyName, propertyType, setter) in injectables) - { - var serviceInstance = serviceProvider.GetService(propertyType); - if (serviceInstance == null) - { - throw new InvalidOperationException($"Cannot provide a value for property " + - $"'{propertyName}' on type '{type.FullName}'. There is no " + - $"registered service of type '{propertyType}'."); - } - - setter.SetValue(component, serviceInstance); - } - } - } - } -} diff --git a/src/Components/Components/src/Dispatcher.cs b/src/Components/Components/src/Dispatcher.cs deleted file mode 100644 index 88ba020813..0000000000 --- a/src/Components/Components/src/Dispatcher.cs +++ /dev/null @@ -1,90 +0,0 @@ -// 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.Rendering; -using Microsoft.AspNetCore.Components.RenderTree; - -namespace Microsoft.AspNetCore.Components -{ - /// - /// Dispatches external actions to be executed on the context of a . - /// - public abstract class Dispatcher - { - /// - /// Creates a default instance of . - /// - /// A instance. - public static Dispatcher CreateDefault() => new RendererSynchronizationContextDispatcher(); - - /// - /// Provides notifications of unhandled exceptions that occur within the dispatcher. - /// - internal event UnhandledExceptionEventHandler UnhandledException; - - /// - /// Validates that the currently executing code is running inside the dispatcher. - /// - public void AssertAccess() - { - if (!CheckAccess()) - { - throw new InvalidOperationException( - "The current thread is not associated with the Dispatcher. " + - "Use InvokeAsync() to switch execution to the Dispatcher when " + - "triggering rendering or component state."); - } - } - - /// - /// Returns a value that determines whether using the dispatcher to invoke a work item is required - /// from the current context. - /// - /// true if invoking is required, otherwise false. - public abstract bool CheckAccess(); - - /// - /// Invokes the given in the context of the associated . - /// - /// The action to execute. - /// A that will be completed when the action has finished executing. - public abstract Task InvokeAsync(Action workItem); - - /// - /// Invokes the given in the context of the associated . - /// - /// The asynchronous action to execute. - /// A that will be completed when the action has finished executing. - public abstract Task InvokeAsync(Func workItem); - - /// - /// Invokes the given in the context of the associated . - /// - /// The function to execute. - /// A that will be completed when the function has finished executing. - public abstract Task InvokeAsync(Func workItem); - - /// - /// Invokes the given in the context of the associated . - /// - /// The asynchronous function to execute. - /// A that will be completed when the function has finished executing. - public abstract Task InvokeAsync(Func> workItem); - - /// - /// Called to notify listeners of an unhandled exception. - /// - /// The . - protected void OnUnhandledException(UnhandledExceptionEventArgs e) - { - if (e is null) - { - throw new ArgumentNullException(nameof(e)); - } - - UnhandledException?.Invoke(this, e); - } - } -} diff --git a/src/Components/Components/src/ElementReference.cs b/src/Components/Components/src/ElementReference.cs deleted file mode 100644 index e25c673be7..0000000000 --- a/src/Components/Components/src/ElementReference.cs +++ /dev/null @@ -1,55 +0,0 @@ -// 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.Globalization; -using System.Threading; - -namespace Microsoft.AspNetCore.Components -{ - /// - /// Represents a reference to a rendered element. - /// - public readonly struct ElementReference - { - private static long _nextIdForWebAssemblyOnly = 1; - - /// - /// Gets a unique identifier for . - /// - /// - /// The Id is unique at least within the scope of a given user/circuit. - /// This property is public to support Json serialization and should not be used by user code. - /// - public string Id { get; } - - public ElementReference(string id) - { - Id = id; - } - - internal static ElementReference CreateWithUniqueId() - => new ElementReference(CreateUniqueId()); - - private static string CreateUniqueId() - { - if (PlatformInfo.IsWebAssembly) - { - // On WebAssembly there's only one user, so it's fine to expose the number - // of IDs that have been assigned, and this is cheaper than creating a GUID. - // It's unfortunate that this still involves a heap allocation. If that becomes - // a problem we could extend RenderTreeFrame to have both "string" and "long" - // fields for ElementRefCaptureId, of which only one would be in use depending - // on the platform. - var id = Interlocked.Increment(ref _nextIdForWebAssemblyOnly); - return id.ToString(CultureInfo.InvariantCulture); - } - else - { - // For remote rendering, it's important not to disclose any cross-user state, - // such as the number of IDs that have been assigned. - return Guid.NewGuid().ToString("D", CultureInfo.InvariantCulture); - } - } - } -} diff --git a/src/Components/Components/src/EventCallback.cs b/src/Components/Components/src/EventCallback.cs deleted file mode 100644 index 3ba05ceaba..0000000000 --- a/src/Components/Components/src/EventCallback.cs +++ /dev/null @@ -1,69 +0,0 @@ -// 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; - -namespace Microsoft.AspNetCore.Components -{ - /// - /// A bound event handler delegate. - /// - public readonly struct EventCallback : IEventCallback - { - /// - /// Gets a reference to the . - /// - public static readonly EventCallbackFactory Factory = new EventCallbackFactory(); - - /// - /// Gets an empty . - /// - public static readonly EventCallback Empty = new EventCallback(null, (Action)(() => { })); - - internal readonly MulticastDelegate Delegate; - internal readonly IHandleEvent Receiver; - - /// - /// Creates the new . - /// - /// The event receiver. - /// The delegate to bind. - public EventCallback(IHandleEvent receiver, MulticastDelegate @delegate) - { - Receiver = receiver; - Delegate = @delegate; - } - - /// - /// Gets a value that indicates whether the delegate associated with this event dispatcher is non-null. - /// - public bool HasDelegate => Delegate != null; - - // This is a hint to the runtime that Receiver is a different object than what - // Delegate.Target points to. This allows us to avoid boxing the command object - // when building the render tree. See logic where this is used. - internal bool RequiresExplicitReceiver => Receiver != null && !object.ReferenceEquals(Receiver, Delegate?.Target); - - /// - /// Invokes the delegate associated with this binding and dispatches an event notification to the - /// appropriate component. - /// - /// The argument. - /// A which completes asynchronously once event processing has completed. - public Task InvokeAsync(object arg) - { - if (Receiver == null) - { - return EventCallbackWorkItem.InvokeAsync(Delegate, arg); - } - - return Receiver.HandleEventAsync(new EventCallbackWorkItem(Delegate), arg); - } - - object IEventCallback.UnpackForRenderTree() - { - return RequiresExplicitReceiver ? (object)this : Delegate; - } - } -} diff --git a/src/Components/Components/src/EventCallbackFactory.cs b/src/Components/Components/src/EventCallbackFactory.cs deleted file mode 100644 index 1b53376b85..0000000000 --- a/src/Components/Components/src/EventCallbackFactory.cs +++ /dev/null @@ -1,241 +0,0 @@ -// 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.ComponentModel; -using System.Threading.Tasks; - -namespace Microsoft.AspNetCore.Components -{ - /// - /// A factory for creating and - /// instances. - /// - public sealed class EventCallbackFactory - { - /// - /// Returns the provided . For internal framework use only. - /// - /// - /// - /// - [EditorBrowsable(EditorBrowsableState.Never)] - public EventCallback Create(object receiver, EventCallback callback) - { - if (receiver == null) - { - throw new ArgumentNullException(nameof(receiver)); - } - - return callback; - } - - /// - /// Creates an for the provided and - /// . - /// - /// The event receiver. - /// The event callback. - /// The . - public EventCallback Create(object receiver, Action callback) - { - if (receiver == null) - { - throw new ArgumentNullException(nameof(receiver)); - } - - return CreateCore(receiver, callback); - } - - /// - /// Creates an for the provided and - /// . - /// - /// The event receiver. - /// The event callback. - /// The . - public EventCallback Create(object receiver, Action callback) - { - if (receiver == null) - { - throw new ArgumentNullException(nameof(receiver)); - } - - return CreateCore(receiver, callback); - } - - /// - /// Creates an for the provided and - /// . - /// - /// The event receiver. - /// The event callback. - /// The . - public EventCallback Create(object receiver, Func callback) - { - if (receiver == null) - { - throw new ArgumentNullException(nameof(receiver)); - } - - return CreateCore(receiver, callback); - } - - /// - /// Creates an for the provided and - /// . - /// - /// The event receiver. - /// The event callback. - /// The . - public EventCallback Create(object receiver, Func callback) - { - if (receiver == null) - { - throw new ArgumentNullException(nameof(receiver)); - } - - return CreateCore(receiver, callback); - } - - /// - /// Returns the provided . For internal framework use only. - /// - /// - /// - /// - [EditorBrowsable(EditorBrowsableState.Never)] - public EventCallback Create(object receiver, EventCallback callback) - { - if (receiver == null) - { - throw new ArgumentNullException(nameof(receiver)); - } - - return new EventCallback(callback.Receiver, callback.Delegate); - } - - /// - /// Returns the provided . For internal framework use only. - /// - /// - /// - /// - [EditorBrowsable(EditorBrowsableState.Never)] - public EventCallback Create(object receiver, EventCallback callback) - { - if (receiver == null) - { - throw new ArgumentNullException(nameof(receiver)); - } - - return callback; - } - - /// - /// Creates an for the provided and - /// . - /// - /// The event receiver. - /// The event callback. - /// The . - public EventCallback Create(object receiver, Action callback) - { - if (receiver == null) - { - throw new ArgumentNullException(nameof(receiver)); - } - - return CreateCore(receiver, callback); - } - - /// - /// Creates an for the provided and - /// . - /// - /// The event receiver. - /// The event callback. - /// The . - public EventCallback Create(object receiver, Action callback) - { - if (receiver == null) - { - throw new ArgumentNullException(nameof(receiver)); - } - - return CreateCore(receiver, callback); - } - - /// - /// Creates an for the provided and - /// . - /// - /// The event receiver. - /// The event callback. - /// The . - public EventCallback Create(object receiver, Func callback) - { - if (receiver == null) - { - throw new ArgumentNullException(nameof(receiver)); - } - - return CreateCore(receiver, callback); - } - - /// - /// Creates an for the provided and - /// . - /// - /// The event receiver. - /// The event callback. - /// The . - public EventCallback Create(object receiver, Func callback) - { - if (receiver == null) - { - throw new ArgumentNullException(nameof(receiver)); - } - - return CreateCore(receiver, callback); - } - - /// - /// Creates an for the provided and - /// . For internal framework use only. - /// - /// - /// - /// - /// - [EditorBrowsable(EditorBrowsableState.Never)] - public EventCallback CreateInferred(object receiver, Action callback, TValue value) - { - return Create(receiver, callback); - } - - /// - /// Creates an for the provided and - /// . For internal framework use only. - /// - /// - /// - /// - /// - [EditorBrowsable(EditorBrowsableState.Never)] - public EventCallback CreateInferred(object receiver, Func callback, TValue value) - { - return Create(receiver, callback); - } - - private EventCallback CreateCore(object receiver, MulticastDelegate callback) - { - return new EventCallback(callback?.Target as IHandleEvent ?? receiver as IHandleEvent, callback); - } - - private EventCallback CreateCore(object receiver, MulticastDelegate callback) - { - return new EventCallback(callback?.Target as IHandleEvent ?? receiver as IHandleEvent, callback); - } - } -} diff --git a/src/Components/Components/src/EventCallbackFactoryBinderExtensions.cs b/src/Components/Components/src/EventCallbackFactoryBinderExtensions.cs deleted file mode 100644 index 99eac1965a..0000000000 --- a/src/Components/Components/src/EventCallbackFactoryBinderExtensions.cs +++ /dev/null @@ -1,539 +0,0 @@ -// 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.Globalization; -using static Microsoft.AspNetCore.Components.BindConverter; - -namespace Microsoft.AspNetCore.Components -{ - /// - /// Contains extension methods for two-way binding using . For internal use only. - /// - // - // NOTE: for number parsing, the HTML5 spec dictates that the DOM will represent - // number values as floating point numbers using `.` as the period separator. This is NOT culture senstive. - // Put another way, the user might see `,` as their decimal separator, but the value available in events - // to JS code is always simpilar to what .NET parses with InvariantCulture. - // - // See: https://www.w3.org/TR/html5/sec-forms.html#number-state-typenumber - // See: https://www.w3.org/TR/html5/infrastructure.html#valid-floating-point-number - // - // For now we're not necessarily handling this correctly since we parse the same way for number and text. - public static class EventCallbackFactoryBinderExtensions - { - /// - /// For internal use only. - /// - /// - /// - /// - /// - /// - /// - public static EventCallback CreateBinder( - this EventCallbackFactory factory, - object receiver, - Action setter, - string existingValue, - CultureInfo culture = null) - { - return CreateBinderCore(factory, receiver, setter, culture, ConvertToString); - } - - /// - /// For internal use only. - /// - /// - /// - /// - /// - /// - /// - public static EventCallback CreateBinder( - this EventCallbackFactory factory, - object receiver, - Action setter, - bool existingValue, - CultureInfo culture = null) - { - return CreateBinderCore(factory, receiver, setter, culture, ConvertToBool); - } - - /// - /// For internal use only. - /// - /// - /// - /// - /// - /// - /// - public static EventCallback CreateBinder( - this EventCallbackFactory factory, - object receiver, - Action setter, - bool? existingValue, - CultureInfo culture = null) - { - return CreateBinderCore(factory, receiver, setter, culture, ConvertToNullableBool); - } - - /// - /// For internal use only. - /// - /// - /// - /// - /// - /// - /// - public static EventCallback CreateBinder( - this EventCallbackFactory factory, - object receiver, - Action setter, - int existingValue, - CultureInfo culture = null) - { - return CreateBinderCore(factory, receiver, setter, culture, ConvertToInt); - } - - /// - /// For internal use only. - /// - /// - /// - /// - /// - /// - /// - public static EventCallback CreateBinder( - this EventCallbackFactory factory, - object receiver, - Action setter, - int? existingValue, - CultureInfo culture = null) - { - return CreateBinderCore(factory, receiver, setter, culture, ConvertToNullableInt); - } - - /// - /// For internal use only. - /// - /// - /// - /// - /// - /// - /// - public static EventCallback CreateBinder( - this EventCallbackFactory factory, - object receiver, - Action setter, - long existingValue, - CultureInfo culture = null) - { - return CreateBinderCore(factory, receiver, setter, culture, ConvertToLong); - } - - /// - /// For internal use only. - /// - /// - /// - /// - /// - /// - /// - public static EventCallback CreateBinder( - this EventCallbackFactory factory, - object receiver, - Action setter, - long? existingValue, - CultureInfo culture = null) - { - return CreateBinderCore(factory, receiver, setter, culture, ConvertToNullableLong); - } - - /// - /// For internal use only. - /// - /// - /// - /// - /// - /// - /// - public static EventCallback CreateBinder( - this EventCallbackFactory factory, - object receiver, - Action setter, - float existingValue, - CultureInfo culture = null) - { - return CreateBinderCore(factory, receiver, setter, culture, ConvertToFloat); - } - - /// - /// For internal use only. - /// - /// - /// - /// - /// - /// - /// - public static EventCallback CreateBinder( - this EventCallbackFactory factory, - object receiver, - Action setter, - float? existingValue, - CultureInfo culture = null) - { - return CreateBinderCore(factory, receiver, setter, culture, ConvertToNullableFloat); - } - - /// - /// For internal use only. - /// - /// - /// - /// - /// - /// - /// - public static EventCallback CreateBinder( - this EventCallbackFactory factory, - object receiver, - Action setter, - double existingValue, - CultureInfo culture = null) - { - return CreateBinderCore(factory, receiver, setter, culture, ConvertToDoubleDelegate); - } - - /// - /// For internal use only. - /// - /// - /// - /// - /// - /// - /// - public static EventCallback CreateBinder( - this EventCallbackFactory factory, - object receiver, - Action setter, - double? existingValue, - CultureInfo culture = null) - { - return CreateBinderCore(factory, receiver, setter, culture, ConvertToNullableDoubleDelegate); - } - - /// - /// For internal use only. - /// - /// - /// - /// - /// - /// - /// - public static EventCallback CreateBinder( - this EventCallbackFactory factory, - object receiver, - Action setter, - decimal existingValue, - CultureInfo culture = null) - { - return CreateBinderCore(factory, receiver, setter, culture, ConvertToDecimal); - } - - /// - /// For internal use only. - /// - /// - /// - /// - /// - /// - /// - public static EventCallback CreateBinder( - this EventCallbackFactory factory, - object receiver, - Action setter, - decimal? existingValue, - CultureInfo culture = null) - { - return CreateBinderCore(factory, receiver, setter, culture, ConvertToNullableDecimal); - } - - /// - /// For internal use only. - /// - /// - /// - /// - /// - /// - /// - public static EventCallback CreateBinder( - this EventCallbackFactory factory, - object receiver, - Action setter, - DateTime existingValue, - CultureInfo culture = null) - { - return CreateBinderCore(factory, receiver, setter, culture, ConvertToDateTime); - } - - /// - /// For internal use only. - /// - /// - /// - /// - /// - /// - /// - /// - public static EventCallback CreateBinder( - this EventCallbackFactory factory, - object receiver, - Action setter, - DateTime existingValue, - string format, - CultureInfo culture = null) - { - return CreateBinderCore(factory, receiver, setter, culture, format, ConvertToDateTimeWithFormat); - } - - /// - /// For internal use only. - /// - /// - /// - /// - /// - /// - /// - public static EventCallback CreateBinder( - this EventCallbackFactory factory, - object receiver, - Action setter, - DateTime? existingValue, - CultureInfo culture = null) - { - return CreateBinderCore(factory, receiver, setter, culture, ConvertToNullableDateTime); - } - - /// - /// For internal use only. - /// - /// - /// - /// - /// - /// - /// - /// - public static EventCallback CreateBinder( - this EventCallbackFactory factory, - object receiver, - Action setter, - DateTime? existingValue, - string format, - CultureInfo culture = null) - { - return CreateBinderCore(factory, receiver, setter, culture, format, ConvertToNullableDateTimeWithFormat); - } - - /// - /// For internal use only. - /// - /// - /// - /// - /// - /// - /// - public static EventCallback CreateBinder( - this EventCallbackFactory factory, - object receiver, - Action setter, - DateTimeOffset existingValue, - CultureInfo culture = null) - { - return CreateBinderCore(factory, receiver, setter, culture, ConvertToDateTimeOffset); - } - - /// - /// For internal use only. - /// - /// - /// - /// - /// - /// - /// - /// - public static EventCallback CreateBinder( - this EventCallbackFactory factory, - object receiver, - Action setter, - DateTimeOffset existingValue, - string format, - CultureInfo culture = null) - { - return CreateBinderCore(factory, receiver, setter, culture, format, ConvertToDateTimeOffsetWithFormat); - } - - /// - /// For internal use only. - /// - /// - /// - /// - /// - /// - /// - public static EventCallback CreateBinder( - this EventCallbackFactory factory, - object receiver, - Action setter, - DateTimeOffset? existingValue, - CultureInfo culture = null) - { - return CreateBinderCore(factory, receiver, setter, culture, ConvertToNullableDateTimeOffset); - } - - /// - /// For internal use only. - /// - /// - /// - /// - /// - /// - /// - /// - public static EventCallback CreateBinder( - this EventCallbackFactory factory, - object receiver, - Action setter, - DateTimeOffset? existingValue, - string format, - CultureInfo culture = null) - { - return CreateBinderCore(factory, receiver, setter, culture, format, ConvertToNullableDateTimeOffsetWithFormat); - } - - /// - /// For internal use only. - /// - /// - /// - /// - /// - /// - /// - /// - public static EventCallback CreateBinder( - this EventCallbackFactory factory, - object receiver, - Action setter, - T existingValue, - CultureInfo culture = null) - { - return CreateBinderCore(factory, receiver, setter, culture, ParserDelegateCache.Get()); - } - - private static EventCallback CreateBinderCore( - this EventCallbackFactory factory, - object receiver, - Action setter, - CultureInfo culture, - BindConverter.BindParser converter) - { - Action callback = e => - { - T value = default; - var converted = false; - try - { - converted = converter(e.Value, culture, out value); - } - catch - { - } - - // We only invoke the setter if the conversion didn't throw, or if the newly-entered value is empty. - // If the user entered some non-empty value we couldn't parse, we leave the state of the .NET field - // unchanged, which for a two-way binding results in the UI reverting to its previous valid state - // because the diff will see the current .NET output no longer matches the render tree since we - // patched it to reflect the state of the UI. - // - // This reversion behavior is valuable because alternatives are problematic: - // - If we assigned default(T) on failure, the user would lose whatever data they were editing, - // for example if they accidentally pressed an alphabetical key while editing a number with - // @bind:event="oninput" - // - If the diff mechanism didn't revert to the previous good value, the user wouldn't necessarily - // know that the data they are submitting is different from what they think they've typed - if (converted) - { - setter(value); - } - else if (string.Empty.Equals(e.Value)) - { - setter(default); - } - }; - return factory.Create(receiver, callback); - } - - private static EventCallback CreateBinderCore( - this EventCallbackFactory factory, - object receiver, - Action setter, - CultureInfo culture, - string format, - BindConverter.BindParserWithFormat converter) - { - Action callback = e => - { - T value = default; - var converted = false; - try - { - converted = converter(e.Value, culture, format, out value); - } - catch - { - } - - // We only invoke the setter if the conversion didn't throw, or if the newly-entered value is empty. - // If the user entered some non-empty value we couldn't parse, we leave the state of the .NET field - // unchanged, which for a two-way binding results in the UI reverting to its previous valid state - // because the diff will see the current .NET output no longer matches the render tree since we - // patched it to reflect the state of the UI. - // - // This reversion behavior is valuable because alternatives are problematic: - // - If we assigned default(T) on failure, the user would lose whatever data they were editing, - // for example if they accidentally pressed an alphabetical key while editing a number with - // @bind:event="oninput" - // - If the diff mechanism didn't revert to the previous good value, the user wouldn't necessarily - // know that the data they are submitting is different from what they think they've typed - if (converted) - { - setter(value); - } - else if (string.Empty.Equals(e.Value)) - { - setter(default); - } - }; - return factory.Create(receiver, callback); - } - } -} diff --git a/src/Components/Components/src/EventCallbackFactoryEventArgsExtensions.cs b/src/Components/Components/src/EventCallbackFactoryEventArgsExtensions.cs deleted file mode 100644 index d0c4aec303..0000000000 --- a/src/Components/Components/src/EventCallbackFactoryEventArgsExtensions.cs +++ /dev/null @@ -1,86 +0,0 @@ -// 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; - -namespace Microsoft.AspNetCore.Components -{ - /// - /// Provides extension methods for and types. - /// - public static class EventCallbackFactoryEventArgsExtensions - { - /// - /// Creates an for the provided and - /// . - /// - /// The . - /// The event receiver. - /// The event callback. - /// The . - public static EventCallback Create(this EventCallbackFactory factory, object receiver, Action callback) - { - if (factory == null) - { - throw new ArgumentNullException(nameof(factory)); - } - - return factory.Create(receiver, callback); - } - - /// - /// Creates an for the provided and - /// . - /// - /// The . - /// The event receiver. - /// The event callback. - /// The . - public static EventCallback Create(this EventCallbackFactory factory, object receiver, Func callback) - { - if (factory == null) - { - throw new ArgumentNullException(nameof(factory)); - } - - return factory.Create(receiver, callback); - } - - /// - /// Creates an for the provided and - /// . - /// - /// The . - /// The event receiver. - /// The event callback. - /// The . - public static EventCallback Create(this EventCallbackFactory factory, object receiver, Action callback) - { - if (factory == null) - { - throw new ArgumentNullException(nameof(factory)); - } - - return factory.Create(receiver, callback); - } - - /// - /// Creates an for the provided and - /// . - /// - /// The . - /// The event receiver. - /// The event callback. - /// The . - public static EventCallback Create(this EventCallbackFactory factory, object receiver, Func callback) - { - if (factory == null) - { - throw new ArgumentNullException(nameof(factory)); - } - - return factory.Create(receiver, callback); - } - } -} diff --git a/src/Components/Components/src/EventCallbackOfT.cs b/src/Components/Components/src/EventCallbackOfT.cs deleted file mode 100644 index 918d8d62e2..0000000000 --- a/src/Components/Components/src/EventCallbackOfT.cs +++ /dev/null @@ -1,69 +0,0 @@ -// 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; - -namespace Microsoft.AspNetCore.Components -{ - /// - /// A bound event handler delegate. - /// - public readonly struct EventCallback : IEventCallback - { - /// - /// Gets an empty . - /// - public static readonly EventCallback Empty = new EventCallback(null, (Action)(() => { })); - - internal readonly MulticastDelegate Delegate; - internal readonly IHandleEvent Receiver; - - /// - /// Creates the new . - /// - /// The event receiver. - /// The delegate to bind. - public EventCallback(IHandleEvent receiver, MulticastDelegate @delegate) - { - Receiver = receiver; - Delegate = @delegate; - } - - /// - /// Gets a value that indicates whether the delegate associated with this event dispatcher is non-null. - /// - public bool HasDelegate => Delegate != null; - - // This is a hint to the runtime that Receiver is a different object than what - // Delegate.Target points to. This allows us to avoid boxing the command object - // when building the render tree. See logic where this is used. - internal bool RequiresExplicitReceiver => Receiver != null && !object.ReferenceEquals(Receiver, Delegate?.Target); - - /// - /// Invokes the delegate associated with this binding and dispatches an event notification to the - /// appropriate component. - /// - /// The argument. - /// A which completes asynchronously once event processing has completed. - public Task InvokeAsync(TValue arg) - { - if (Receiver == null) - { - return EventCallbackWorkItem.InvokeAsync(Delegate, arg); - } - - return Receiver.HandleEventAsync(new EventCallbackWorkItem(Delegate), arg); - } - - internal EventCallback AsUntyped() - { - return new EventCallback(Receiver ?? Delegate?.Target as IHandleEvent, Delegate); - } - - object IEventCallback.UnpackForRenderTree() - { - return RequiresExplicitReceiver ? (object)AsUntyped() : Delegate; - } - } -} diff --git a/src/Components/Components/src/EventCallbackWorkItem.cs b/src/Components/Components/src/EventCallbackWorkItem.cs deleted file mode 100644 index bb7c8320b2..0000000000 --- a/src/Components/Components/src/EventCallbackWorkItem.cs +++ /dev/null @@ -1,79 +0,0 @@ -// 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.Reflection; -using System.Threading.Tasks; - -namespace Microsoft.AspNetCore.Components -{ - /// - /// Wraps a callback delegate associated with an event. - /// - public readonly struct EventCallbackWorkItem - { - /// - /// An empty . - /// - public static readonly EventCallbackWorkItem Empty = new EventCallbackWorkItem(null); - - private readonly MulticastDelegate _delegate; - - /// - /// Creates a new with the provided . - /// - /// The callback delegate. - public EventCallbackWorkItem(MulticastDelegate @delegate) - { - _delegate = @delegate; - } - - /// - /// Invokes the delegate associated with this . - /// - /// The argument to provide to the delegate. May be null. - /// A then will complete asynchronously once the delegate has completed. - public Task InvokeAsync(object arg) - { - return InvokeAsync(_delegate, arg); - } - - internal static Task InvokeAsync(MulticastDelegate @delegate, T arg) - { - switch (@delegate) - { - case null: - return Task.CompletedTask; - - case Action action: - action.Invoke(); - return Task.CompletedTask; - - case Action actionEventArgs: - actionEventArgs.Invoke(arg); - return Task.CompletedTask; - - case Func func: - return func.Invoke(); - - case Func funcEventArgs: - return funcEventArgs.Invoke(arg); - - default: - { - try - { - return @delegate.DynamicInvoke(arg) as Task ?? Task.CompletedTask; - } - catch (TargetInvocationException e) - { - // Since we fell into the DynamicInvoke case, any exception will be wrapped - // in a TIE. We can expect this to be thrown synchronously, so it's low overhead - // to unwrap it. - return Task.FromException(e.InnerException); - } - } - } - } - } -} diff --git a/src/Components/Components/src/EventHandlerAttribute.cs b/src/Components/Components/src/EventHandlerAttribute.cs deleted file mode 100644 index 67307fb9ef..0000000000 --- a/src/Components/Components/src/EventHandlerAttribute.cs +++ /dev/null @@ -1,68 +0,0 @@ -// 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.AspNetCore.Components -{ - /// - /// Associates an event argument type with an event attribute name. - /// - [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)] - public sealed class EventHandlerAttribute : Attribute - { - /// - /// Constructs an instance of . - /// - /// - /// - public EventHandlerAttribute(string attributeName, Type eventArgsType) : this(attributeName, eventArgsType, false, false) - { - } - - /// - /// Constructs an instance of . - /// - /// - /// - /// - /// - public EventHandlerAttribute(string attributeName, Type eventArgsType, bool enableStopPropagation, bool enablePreventDefault) - { - if (attributeName == null) - { - throw new ArgumentNullException(nameof(attributeName)); - } - - if (eventArgsType == null) - { - throw new ArgumentNullException(nameof(eventArgsType)); - } - - AttributeName = attributeName; - EventArgsType = eventArgsType; - EnableStopPropagation = enableStopPropagation; - EnablePreventDefault = enablePreventDefault; - } - - /// - /// Gets the attribute name. - /// - public string AttributeName { get; } - - /// - /// Gets the event argument type. - /// - public Type EventArgsType { get; } - - /// - /// Gets the event's ability to stop propagation. - /// - public bool EnableStopPropagation { get; } - - /// - /// Gets the event's ability to prevent default event flow. - /// - public bool EnablePreventDefault { get; } - } -} diff --git a/src/Components/Components/src/ICascadingValueComponent.cs b/src/Components/Components/src/ICascadingValueComponent.cs deleted file mode 100644 index de9da715a2..0000000000 --- a/src/Components/Components/src/ICascadingValueComponent.cs +++ /dev/null @@ -1,24 +0,0 @@ -// 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.AspNetCore.Components.Rendering; -using System; - -namespace Microsoft.AspNetCore.Components -{ - internal interface ICascadingValueComponent - { - // This interface exists only so that CascadingParameterState has a way - // to work with all CascadingValue types regardless of T. - - bool CanSupplyValue(Type valueType, string valueName); - - object CurrentValue { get; } - - bool CurrentValueIsFixed { get; } - - void Subscribe(ComponentState subscriber); - - void Unsubscribe(ComponentState subscriber); - } -} diff --git a/src/Components/Components/src/IComponent.cs b/src/Components/Components/src/IComponent.cs deleted file mode 100644 index 936cd37944..0000000000 --- a/src/Components/Components/src/IComponent.cs +++ /dev/null @@ -1,31 +0,0 @@ -// 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.Threading.Tasks; - -namespace Microsoft.AspNetCore.Components -{ - /// - /// Represents a UI component. - /// - public interface IComponent - { - /// - /// Attaches the component to a . - /// - /// A that allows the component to be rendered. - void Attach(RenderHandle renderHandle); - - /// - /// Sets parameters supplied by the component's parent in the render tree. - /// - /// The parameters. - /// A that completes when the component has finished updating and rendering itself. - /// - /// The method should be passed the entire set of parameter values each - /// time is called. It not required that the caller supply a parameter - /// value for all parameters that are logically understood by the component. - /// - Task SetParametersAsync(ParameterView parameters); - } -} diff --git a/src/Components/Components/src/IEventCallback.cs b/src/Components/Components/src/IEventCallback.cs deleted file mode 100644 index 6c9fcac7a3..0000000000 --- a/src/Components/Components/src/IEventCallback.cs +++ /dev/null @@ -1,13 +0,0 @@ -// 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. - -namespace Microsoft.AspNetCore.Components -{ - // Used to understand boxed generic EventCallbacks - internal interface IEventCallback - { - bool HasDelegate { get; } - - object UnpackForRenderTree(); - } -} diff --git a/src/Components/Components/src/IHandleAfterRender.cs b/src/Components/Components/src/IHandleAfterRender.cs deleted file mode 100644 index 349138519f..0000000000 --- a/src/Components/Components/src/IHandleAfterRender.cs +++ /dev/null @@ -1,19 +0,0 @@ -// 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.Threading.Tasks; - -namespace Microsoft.AspNetCore.Components -{ - /// - /// Interface implemented by components that receive notification that they have been rendered. - /// - public interface IHandleAfterRender - { - /// - /// Notifies the component that it has been rendered. - /// - /// A that represents the asynchronous event handling operation. - Task OnAfterRenderAsync(); - } -} diff --git a/src/Components/Components/src/IHandleEvent.cs b/src/Components/Components/src/IHandleEvent.cs deleted file mode 100644 index 478102cbe8..0000000000 --- a/src/Components/Components/src/IHandleEvent.cs +++ /dev/null @@ -1,23 +0,0 @@ -// 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.Threading.Tasks; - -namespace Microsoft.AspNetCore.Components -{ - /// - /// Interface implemented by components that receive notification of state changes. - /// - public interface IHandleEvent - { - /// - /// Notifies the a state change has been triggered. - /// - /// The associated with this event. - /// The argument associated with this event. - /// - /// A that completes once the component has processed the state change. - /// - Task HandleEventAsync(EventCallbackWorkItem item, object arg); - } -} diff --git a/src/Components/Components/src/InjectAttribute.cs b/src/Components/Components/src/InjectAttribute.cs deleted file mode 100644 index f18381fe9c..0000000000 --- a/src/Components/Components/src/InjectAttribute.cs +++ /dev/null @@ -1,16 +0,0 @@ -// 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.AspNetCore.Components -{ - /// - /// Indicates that the associated property should have a value injected from the - /// service provider during initialization. - /// - [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)] - public sealed class InjectAttribute : Attribute - { - } -} diff --git a/src/Components/Components/src/LayoutAttribute.cs b/src/Components/Components/src/LayoutAttribute.cs deleted file mode 100644 index 8e4fa78922..0000000000 --- a/src/Components/Components/src/LayoutAttribute.cs +++ /dev/null @@ -1,40 +0,0 @@ -// 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.AspNetCore.Components -{ - /// - /// Indicates that the associated component type uses a specified layout. - /// - [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)] - public sealed class LayoutAttribute : Attribute - { - /// - /// Constructs an instance of . - /// - /// The type of the layout. - public LayoutAttribute(Type layoutType) - { - LayoutType = layoutType ?? throw new ArgumentNullException(nameof(layoutType)); - - if (!typeof(IComponent).IsAssignableFrom(layoutType)) - { - throw new ArgumentException($"Invalid layout type: {layoutType.FullName} " + - $"does not implement {typeof(IComponent).FullName}."); - } - - // Note that we can't validate its acceptance of a 'Body' parameter at this stage, - // because the contract doesn't force them to be known statically. However it will - // be a runtime error if the referenced component type rejects the 'Body' parameter - // when it gets used. - } - - /// - /// The type of the layout. The type must implement - /// and must accept a parameter with the name 'Body'. - /// - public Type LayoutType { get; private set; } - } -} diff --git a/src/Components/Components/src/LayoutComponentBase.cs b/src/Components/Components/src/LayoutComponentBase.cs deleted file mode 100644 index 776b97b280..0000000000 --- a/src/Components/Components/src/LayoutComponentBase.cs +++ /dev/null @@ -1,21 +0,0 @@ -// 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. - -namespace Microsoft.AspNetCore.Components -{ - /// - /// Optional base class for components that represent a layout. - /// Alternatively, components may implement directly - /// and declare their own parameter named . - /// - public abstract class LayoutComponentBase : ComponentBase - { - internal const string BodyPropertyName = nameof(Body); - - /// - /// Gets the content to be rendered inside the layout. - /// - [Parameter] - public RenderFragment Body { get; set; } - } -} diff --git a/src/Components/Components/src/LayoutView.cs b/src/Components/Components/src/LayoutView.cs deleted file mode 100644 index 7b88d181f0..0000000000 --- a/src/Components/Components/src/LayoutView.cs +++ /dev/null @@ -1,77 +0,0 @@ -// 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.Reflection; -using System.Threading.Tasks; - -namespace Microsoft.AspNetCore.Components -{ - /// - /// Displays the specified content inside the specified layout and any further - /// nested layouts. - /// - public class LayoutView : IComponent - { - private static readonly RenderFragment EmptyRenderFragment = builder => { }; - - private RenderHandle _renderHandle; - - /// - /// Gets or sets the content to display. - /// - [Parameter] - public RenderFragment ChildContent { get; set; } - - /// - /// Gets or sets the type of the layout in which to display the content. - /// The type must implement and accept a parameter named . - /// - [Parameter] - public Type Layout { get; set; } - - /// - public void Attach(RenderHandle renderHandle) - { - _renderHandle = renderHandle; - } - - /// - public Task SetParametersAsync(ParameterView parameters) - { - parameters.SetParameterProperties(this); - Render(); - return Task.CompletedTask; - } - - private void Render() - { - // In the middle goes the supplied content - var fragment = ChildContent ?? EmptyRenderFragment; - - // Then repeatedly wrap that in each layer of nested layout until we get - // to a layout that has no parent - var layoutType = Layout; - while (layoutType != null) - { - fragment = WrapInLayout(layoutType, fragment); - layoutType = GetParentLayoutType(layoutType); - } - - _renderHandle.Render(fragment); - } - - private static RenderFragment WrapInLayout(Type layoutType, RenderFragment bodyParam) - { - return builder => - { - builder.OpenComponent(0, layoutType); - builder.AddAttribute(1, LayoutComponentBase.BodyPropertyName, bodyParam); - builder.CloseComponent(); - }; - } - - private static Type GetParentLayoutType(Type type) - => type.GetCustomAttribute()?.LayoutType; - } -} diff --git a/src/Components/Components/src/LocationChangeException.cs b/src/Components/Components/src/LocationChangeException.cs deleted file mode 100644 index 13010eb5c1..0000000000 --- a/src/Components/Components/src/LocationChangeException.cs +++ /dev/null @@ -1,23 +0,0 @@ -// 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.AspNetCore.Components -{ - /// - /// An exception thrown when throws an exception. - /// - public sealed class LocationChangeException : Exception - { - /// - /// Creates a new instance of . - /// - /// The exception message. - /// The inner exception. - public LocationChangeException(string message, Exception innerException) - : base(message, innerException) - { - } - } -} diff --git a/src/Components/Components/src/MarkupString.cs b/src/Components/Components/src/MarkupString.cs deleted file mode 100644 index c0f9c8af0a..0000000000 --- a/src/Components/Components/src/MarkupString.cs +++ /dev/null @@ -1,36 +0,0 @@ -// 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. - -namespace Microsoft.AspNetCore.Components -{ - /// - /// A string value that can be rendered as markup such as HTML. - /// - public readonly struct MarkupString - { - /// - /// Constructs an instance of . - /// - /// The value for the new instance. - public MarkupString(string value) - { - Value = value; - } - - /// - /// Gets the value of the . - /// - public string Value { get; } - - /// - /// Casts a to a . - /// - /// The value. - public static explicit operator MarkupString(string value) - => new MarkupString(value); - - /// - public override string ToString() - => Value ?? string.Empty; - } -} diff --git a/src/Components/Components/src/Microsoft.AspNetCore.Components.csproj b/src/Components/Components/src/Microsoft.AspNetCore.Components.csproj deleted file mode 100644 index 4c0a31a3f6..0000000000 --- a/src/Components/Components/src/Microsoft.AspNetCore.Components.csproj +++ /dev/null @@ -1,60 +0,0 @@ - - - - netstandard2.0;$(DefaultNetCoreTargetFramework) - $(DefaultNetCoreTargetFramework) - Components feature for ASP.NET Core. - true - true - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Microsoft.AspNetCore.Components.multitarget.nuspec - Microsoft.AspNetCore.Components.netcoreapp.nuspec - $(GenerateNuspecDependsOn);_GetNuspecDependencyPackageVersions - - - - - - - - - - diff --git a/src/Components/Components/src/Microsoft.AspNetCore.Components.multitarget.nuspec b/src/Components/Components/src/Microsoft.AspNetCore.Components.multitarget.nuspec deleted file mode 100644 index 700ea95fa9..0000000000 --- a/src/Components/Components/src/Microsoft.AspNetCore.Components.multitarget.nuspec +++ /dev/null @@ -1,26 +0,0 @@ - - - - $CommonMetadataElements$ - - - - - - - - - - - - - - - - $CommonFileElements$ - - - - - - diff --git a/src/Components/Components/src/Microsoft.AspNetCore.Components.netcoreapp.nuspec b/src/Components/Components/src/Microsoft.AspNetCore.Components.netcoreapp.nuspec deleted file mode 100644 index 8561bc2f2f..0000000000 --- a/src/Components/Components/src/Microsoft.AspNetCore.Components.netcoreapp.nuspec +++ /dev/null @@ -1,20 +0,0 @@ - - - - $CommonMetadataElements$ - - - - - - - - - - $CommonFileElements$ - - - - - - diff --git a/src/Components/Components/src/NavigationException.cs b/src/Components/Components/src/NavigationException.cs deleted file mode 100644 index 5acb891e6f..0000000000 --- a/src/Components/Components/src/NavigationException.cs +++ /dev/null @@ -1,26 +0,0 @@ -// 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.AspNetCore.Components -{ - /// - /// Exception thrown when an is not able to navigate to a different url. - /// - public class NavigationException : Exception - { - /// - /// Initializes a new instance. - /// - public NavigationException(string uri) - { - Location = uri; - } - - /// - /// Gets the uri to which navigation was attempted. - /// - public string Location { get; } - } -} diff --git a/src/Components/Components/src/NavigationManager.cs b/src/Components/Components/src/NavigationManager.cs deleted file mode 100644 index d75077026f..0000000000 --- a/src/Components/Components/src/NavigationManager.cs +++ /dev/null @@ -1,269 +0,0 @@ -// 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 Microsoft.AspNetCore.Components.Routing; - -namespace Microsoft.AspNetCore.Components -{ - /// - /// Provides an abstraction for querying and mananging URI navigation. - /// - public abstract class NavigationManager - { - /// - /// An event that fires when the navigation location has changed. - /// - public event EventHandler LocationChanged - { - add - { - AssertInitialized(); - _locationChanged += value; - } - remove - { - AssertInitialized(); - _locationChanged -= value; - } - } - - private EventHandler _locationChanged; - - // For the baseUri it's worth storing as a System.Uri so we can do operations - // on that type. System.Uri gives us access to the original string anyway. - private Uri _baseUri; - - // The URI. Always represented an absolute URI. - private string _uri; - - private bool _isInitialized; - - /// - /// Gets or sets the current base URI. The is always represented as an absolute URI in string form with trailing slash. - /// Typically this corresponds to the 'href' attribute on the document's <base> element. - /// - /// - /// Setting will not trigger the event. - /// - public string BaseUri - { - get - { - AssertInitialized(); - return _baseUri.OriginalString; - } - protected set - { - if (value != null) - { - value = NormalizeBaseUri(value); - } - - _baseUri = new Uri(value, UriKind.Absolute); - } - } - - /// - /// Gets or sets the current URI. The is always represented as an absolute URI in string form. - /// - /// - /// Setting will not trigger the event. - /// - public string Uri - { - get - { - AssertInitialized(); - return _uri; - } - protected set - { - Validate(_baseUri, value); - _uri = value; - } - } - - /// - /// Navigates to the specified URI. - /// - /// The destination URI. This can be absolute, or relative to the base URI - /// (as returned by ). - /// If true, bypasses client-side routing and forces the browser to load the new page from the server, whether or not the URI would normally be handled by the client-side router. - public void NavigateTo(string uri, bool forceLoad = false) - { - AssertInitialized(); - NavigateToCore(uri, forceLoad); - } - - /// - /// Navigates to the specified URI. - /// - /// The destination URI. This can be absolute, or relative to the base URI - /// (as returned by ). - /// If true, bypasses client-side routing and forces the browser to load the new page from the server, whether or not the URI would normally be handled by the client-side router. - protected abstract void NavigateToCore(string uri, bool forceLoad); - - /// - /// Called to initialize BaseURI and current URI before these values are used for the first time. - /// Override and call this method to dynamically calculate these values. - /// - protected void Initialize(string baseUri, string uri) - { - // Make sure it's possible/safe to call this method from constructors of derived classes. - if (uri == null) - { - throw new ArgumentNullException(nameof(uri)); - } - - if (baseUri == null) - { - throw new ArgumentNullException(nameof(baseUri)); - } - - if (_isInitialized) - { - throw new InvalidOperationException($"'{GetType().Name}' already initialized."); - } - - _isInitialized = true; - - // Setting BaseUri before Uri so they get validated. - BaseUri = baseUri; - Uri = uri; - } - - /// - /// Allows derived classes to lazyly self-initialize. Implementations that support lazy-initialization should override - /// this method and call . - /// - protected virtual void EnsureInitialized() - { - } - - /// - /// Converts a relative URI into an absolute one (by resolving it - /// relative to the current absolute URI). - /// - /// The relative URI. - /// The absolute URI. - public Uri ToAbsoluteUri(string relativeUri) - { - AssertInitialized(); - return new Uri(_baseUri, relativeUri); - } - - /// - /// Given a base URI (e.g., one previously returned by ), - /// converts an absolute URI into one relative to the base URI prefix. - /// - /// An absolute URI that is within the space of the base URI. - /// A relative URI path. - public string ToBaseRelativePath(string uri) - { - if (uri.StartsWith(_baseUri.OriginalString, StringComparison.Ordinal)) - { - // The absolute URI must be of the form "{baseUri}something" (where - // baseUri ends with a slash), and from that we return "something" - return uri.Substring(_baseUri.OriginalString.Length); - } - - var hashIndex = uri.IndexOf('#'); - var uriWithoutHash = hashIndex < 0 ? uri : uri.Substring(0, hashIndex); - if ($"{uriWithoutHash}/".Equals(_baseUri.OriginalString, StringComparison.Ordinal)) - { - // Special case: for the base URI "/something/", if you're at - // "/something" then treat it as if you were at "/something/" (i.e., - // with the trailing slash). It's a bit ambiguous because we don't know - // whether the server would return the same page whether or not the - // slash is present, but ASP.NET Core at least does by default when - // using PathBase. - return uri.Substring(_baseUri.OriginalString.Length - 1); - } - - var message = $"The URI '{uri}' is not contained by the base URI '{_baseUri}'."; - throw new ArgumentException(message); - } - - internal static string NormalizeBaseUri(string baseUri) - { - var lastSlashIndex = baseUri.LastIndexOf('/'); - if (lastSlashIndex >= 0) - { - baseUri = baseUri.Substring(0, lastSlashIndex + 1); - } - - return baseUri; - } - - /// - /// Triggers the event with the current URI value. - /// - protected void NotifyLocationChanged(bool isInterceptedLink) - { - try - { - _locationChanged?.Invoke(this, new LocationChangedEventArgs(_uri, isInterceptedLink)); - } - catch (Exception ex) - { - throw new LocationChangeException("An exception occurred while dispatching a location changed event.", ex); - } - } - - private void AssertInitialized() - { - if (!_isInitialized) - { - EnsureInitialized(); - } - - if (!_isInitialized) - { - throw new InvalidOperationException($"'{GetType().Name}' has not been initialized."); - } - } - - private static bool TryGetLengthOfBaseUriPrefix(Uri baseUri, string uri, out int length) - { - if (uri.StartsWith(baseUri.OriginalString, StringComparison.Ordinal)) - { - // The absolute URI must be of the form "{baseUri}something" (where - // baseUri ends with a slash), and from that we return "something" - length = baseUri.OriginalString.Length; - return true; - } - - var hashIndex = uri.IndexOf('#'); - var uriWithoutHash = hashIndex < 0 ? uri : uri.Substring(0, hashIndex); - if ($"{uriWithoutHash}/".Equals(baseUri.OriginalString, StringComparison.Ordinal)) - { - // Special case: for the base URI "/something/", if you're at - // "/something" then treat it as if you were at "/something/" (i.e., - // with the trailing slash). It's a bit ambiguous because we don't know - // whether the server would return the same page whether or not the - // slash is present, but ASP.NET Core at least does by default when - // using PathBase. - length = baseUri.OriginalString.Length - 1; - return true; - } - - length = 0; - return false; - } - - private static void Validate(Uri baseUri, string uri) - { - if (baseUri == null || uri == null) - { - return; - } - - if (!TryGetLengthOfBaseUriPrefix(baseUri, uri, out _)) - { - var message = $"The URI '{uri}' is not contained by the base URI '{baseUri}'."; - throw new ArgumentException(message); - } - } - } -} diff --git a/src/Components/Components/src/OwningComponentBase.cs b/src/Components/Components/src/OwningComponentBase.cs deleted file mode 100644 index d5bcecb1f7..0000000000 --- a/src/Components/Components/src/OwningComponentBase.cs +++ /dev/null @@ -1,100 +0,0 @@ -// 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 Microsoft.Extensions.DependencyInjection; - -namespace Microsoft.AspNetCore.Components -{ - /// - /// A base class that creates a service provider scope. - /// - /// - /// Use the class as a base class to author components that control - /// the lifetime of a service provider scope. This is useful when using a transient or scoped service that - /// requires disposal such as a repository or database abstraction. Using - /// as a base class ensures that the service provider scope is disposed with the component. - /// - public abstract class OwningComponentBase : ComponentBase, IDisposable - { - private IServiceScope _scope; - - [Inject] IServiceScopeFactory ScopeFactory { get; set; } - - /// - /// Gets a value determining if the component and associated services have been disposed. - /// - protected bool IsDisposed { get; private set; } - - /// - /// Gets the scoped that is associated with this component. - /// - protected IServiceProvider ScopedServices - { - get - { - if (ScopeFactory == null) - { - throw new InvalidOperationException("Services cannot be accessed before the component is initialized."); - } - - if (IsDisposed) - { - throw new ObjectDisposedException(GetType().Name); - } - - _scope ??= ScopeFactory.CreateScope(); - return _scope.ServiceProvider; - } - } - - void IDisposable.Dispose() - { - if (!IsDisposed) - { - _scope?.Dispose(); - _scope = null; - Dispose(disposing: true); - IsDisposed = true; - } - } - - /// - protected virtual void Dispose(bool disposing) - { - } - } - - /// - /// A base class that creates a service provider scope, and resolves a service of type . - /// - /// The service type. - /// - /// Use the class as a base class to author components that control - /// the lifetime of a service or multiple services. This is useful when using a transient or scoped service that - /// requires disposal such as a repository or database abstraction. Using - /// as a base class ensures that the service and relates services that share its scope are disposed with the component. - /// - public abstract class OwningComponentBase : OwningComponentBase, IDisposable - { - private TService _item; - - /// - /// Gets the that is associated with this component. - /// - protected TService Service - { - get - { - if (IsDisposed) - { - throw new ObjectDisposedException(GetType().Name); - } - - // We cache this because we don't know the lifetime. We have to assume that it could be transient. - _item ??= ScopedServices.GetRequiredService(); - return _item; - } - } - } -} diff --git a/src/Components/Components/src/ParameterAttribute.cs b/src/Components/Components/src/ParameterAttribute.cs deleted file mode 100644 index 8001f1cdb3..0000000000 --- a/src/Components/Components/src/ParameterAttribute.cs +++ /dev/null @@ -1,36 +0,0 @@ -// 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.Collections.Generic; -using Microsoft.AspNetCore.Components.Rendering; - -namespace Microsoft.AspNetCore.Components -{ - /// - /// Denotes the target member as a component parameter. - /// - [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)] - public sealed class ParameterAttribute : Attribute - { - /// - /// Gets or sets a value that determines whether the parameter will capture values that - /// don't match any other parameter. - /// - /// - /// - /// allows a component to accept arbitrary additional - /// attributes, and pass them to another component, or some element of the underlying markup. - /// - /// - /// can be used on at most one parameter per component. - /// - /// - /// should only be applied to parameters of a type that - /// can be used with - /// such as . - /// - /// - public bool CaptureUnmatchedValues { get; set; } - } -} diff --git a/src/Components/Components/src/ParameterValue.cs b/src/Components/Components/src/ParameterValue.cs deleted file mode 100644 index c080880de2..0000000000 --- a/src/Components/Components/src/ParameterValue.cs +++ /dev/null @@ -1,35 +0,0 @@ -// 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. - -namespace Microsoft.AspNetCore.Components -{ - /// - /// Represents a single parameter supplied to an - /// by its parent in the render tree. - /// - public readonly struct ParameterValue - { - internal ParameterValue(string name, object value, bool cascading) - { - Name = name; - Value = value; - Cascading = cascading; - } - - /// - /// Gets the name of the parameter. - /// - public string Name { get; } - - /// - /// Gets the value being supplied for the parameter. - /// - public object Value { get; } - - /// - /// Gets a value to indicate whether the parameter is cascading, meaning that it - /// was supplied by a . - /// - public bool Cascading { get; } - } -} diff --git a/src/Components/Components/src/ParameterView.cs b/src/Components/Components/src/ParameterView.cs deleted file mode 100644 index 33f87a5062..0000000000 --- a/src/Components/Components/src/ParameterView.cs +++ /dev/null @@ -1,375 +0,0 @@ -// 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.Collections.Generic; -using Microsoft.AspNetCore.Components.Reflection; -using Microsoft.AspNetCore.Components.Rendering; -using Microsoft.AspNetCore.Components.RenderTree; - -namespace Microsoft.AspNetCore.Components -{ - /// - /// Represents a collection of parameters supplied to an - /// by its parent in the render tree. - /// - public readonly struct ParameterView - { - private const string GeneratedParameterViewElementName = "__ARTIFICIAL_PARAMETER_VIEW"; - private static readonly RenderTreeFrame[] _emptyFrames = new RenderTreeFrame[] - { - RenderTreeFrame.Element(0, string.Empty).WithComponentSubtreeLength(1) - }; - - private static readonly ParameterView _empty = new ParameterView(ParameterViewLifetime.Unbound, _emptyFrames, 0, null); - - private readonly ParameterViewLifetime _lifetime; - private readonly RenderTreeFrame[] _frames; - private readonly int _ownerIndex; - private readonly IReadOnlyList _cascadingParametersOrNull; - - internal ParameterView(in ParameterViewLifetime lifetime, RenderTreeFrame[] frames, int ownerIndex) - : this(lifetime, frames, ownerIndex, null) - { - } - - private ParameterView(in ParameterViewLifetime lifetime, RenderTreeFrame[] frames, int ownerIndex, IReadOnlyList cascadingParametersOrNull) - { - _lifetime = lifetime; - _frames = frames; - _ownerIndex = ownerIndex; - _cascadingParametersOrNull = cascadingParametersOrNull; - } - - /// - /// Gets an empty . - /// - public static ParameterView Empty => _empty; - - internal ParameterViewLifetime Lifetime => _lifetime; - - /// - /// Returns an enumerator that iterates through the . - /// - /// The enumerator. - public Enumerator GetEnumerator() - { - _lifetime.AssertNotExpired(); - return new Enumerator(_frames, _ownerIndex, _cascadingParametersOrNull); - } - - /// - /// Gets the value of the parameter with the specified name. - /// - /// The type of the value. - /// The name of the parameter. - /// Receives the result, if any. - /// True if a matching parameter was found; false otherwise. - public bool TryGetValue(string parameterName, out TValue result) - { - foreach (var entry in this) - { - if (string.Equals(entry.Name, parameterName)) - { - result = (TValue)entry.Value; - return true; - } - } - - result = default; - return false; - } - - /// - /// Gets the value of the parameter with the specified name, or a default value - /// if no such parameter exists in the collection. - /// - /// The type of the value. - /// The name of the parameter. - /// The parameter value if found; otherwise the default value for the specified type. - public TValue GetValueOrDefault(string parameterName) - => GetValueOrDefault(parameterName, default); - - /// - /// Gets the value of the parameter with the specified name, or a specified default value - /// if no such parameter exists in the collection. - /// - /// The type of the value. - /// The name of the parameter. - /// The default value to return if no such parameter exists in the collection. - /// The parameter value if found; otherwise . - public TValue GetValueOrDefault(string parameterName, TValue defaultValue) - => TryGetValue(parameterName, out TValue result) ? result : defaultValue; - - /// - /// Returns a dictionary populated with the contents of the . - /// - /// A dictionary populated with the contents of the . - public IReadOnlyDictionary ToDictionary() - { - var result = new Dictionary(); - foreach (var entry in this) - { - result[entry.Name] = entry.Value; - } - return result; - } - - internal ParameterView WithCascadingParameters(IReadOnlyList cascadingParameters) - => new ParameterView(_lifetime, _frames, _ownerIndex, cascadingParameters); - - // It's internal because there isn't a known use case for user code comparing - // ParameterView instances, and even if there was, it's unlikely it should - // use these equality rules which are designed for their effect on rendering. - internal bool DefinitelyEquals(ParameterView oldParameters) - { - // In general we can't detect mutations on arbitrary objects. We can't trust - // things like .Equals or .GetHashCode because they usually only tell us about - // shallow changes, not deep mutations. So we return false if both: - // [1] All the parameters are known to be immutable (i.e., Type.IsPrimitive - // or is in a known set of common immutable types) - // [2] And all the parameter values are equal to their previous values - // Otherwise be conservative and return false. - // To make this check cheaper, since parameters are virtually always generated in - // a deterministic order, we don't bother to account for reordering, so if any - // of the names don't match sequentially we just return false too. - // - // The logic here may look kind of epic, and would certainly be simpler if we - // used ParameterEnumerator.GetEnumerator(), but it's perf-critical and this - // implementation requires a lot fewer instructions than a GetEnumerator-based one. - - var oldIndex = oldParameters._ownerIndex; - var newIndex = _ownerIndex; - var oldEndIndexExcl = oldIndex + oldParameters._frames[oldIndex].ComponentSubtreeLength; - var newEndIndexExcl = newIndex + _frames[newIndex].ComponentSubtreeLength; - while (true) - { - // First, stop if we've reached the end of either subtree - oldIndex++; - newIndex++; - var oldFinished = oldIndex == oldEndIndexExcl; - var newFinished = newIndex == newEndIndexExcl; - if (oldFinished || newFinished) - { - return oldFinished == newFinished; // Same only if we have same number of parameters - } - else - { - // Since neither subtree has finished, it's safe to read the next frame from both - ref var oldFrame = ref oldParameters._frames[oldIndex]; - ref var newFrame = ref _frames[newIndex]; - - // Stop if we've reached the end of either subtree's sequence of attributes - oldFinished = oldFrame.FrameType != RenderTreeFrameType.Attribute; - newFinished = newFrame.FrameType != RenderTreeFrameType.Attribute; - if (oldFinished || newFinished) - { - return oldFinished == newFinished; // Same only if we have same number of parameters - } - else - { - if (!string.Equals(oldFrame.AttributeName, newFrame.AttributeName, StringComparison.Ordinal)) - { - return false; // Different names - } - - var oldValue = oldFrame.AttributeValue; - var newValue = newFrame.AttributeValue; - if (ChangeDetection.MayHaveChanged(oldValue, newValue)) - { - return false; - } - } - } - } - } - - internal void CaptureSnapshot(ArrayBuilder builder) - { - builder.Clear(); - - var numEntries = 0; - foreach (var entry in this) - { - numEntries++; - } - - // We need to prefix the captured frames with an "owner" frame that - // describes the length of the buffer so that ParameterView - // knows how far to iterate through it. - var owner = RenderTreeFrame.PlaceholderChildComponentWithSubtreeLength(1 + numEntries); - builder.Append(owner); - - if (numEntries > 0) - { - builder.Append(_frames, _ownerIndex + 1, numEntries); - } - } - - /// - /// Creates a new from the given . - /// - /// The with the parameters. - /// A . - public static ParameterView FromDictionary(IDictionary parameters) - { - var frames = new RenderTreeFrame[parameters.Count + 1]; - frames[0] = RenderTreeFrame.Element(0, GeneratedParameterViewElementName) - .WithElementSubtreeLength(frames.Length); - - var i = 0; - foreach (var kvp in parameters) - { - frames[++i] = RenderTreeFrame.Attribute(i, kvp.Key, kvp.Value); - } - - return new ParameterView(ParameterViewLifetime.Unbound, frames, 0); - } - - /// - /// For each parameter property on , updates its value to - /// match the corresponding entry in the . - /// - /// An object that has a public writable property matching each parameter's name and type. - public void SetParameterProperties(object target) - { - if (target is null) - { - throw new ArgumentNullException(nameof(target)); - } - - ComponentProperties.SetProperties(this, target); - } - - /// - /// An enumerator that iterates through a . - /// - - // Note that this intentionally does not implement IEnumerator<>. This is the same pattern as Span<>.Enumerator - // it's valid to foreach over a type that doesn't implement IEnumerator<>. - public struct Enumerator - { - private RenderTreeFrameParameterEnumerator _directParamsEnumerator; - private CascadingParameterEnumerator _cascadingParameterEnumerator; - private bool _isEnumeratingDirectParams; - - internal Enumerator(RenderTreeFrame[] frames, int ownerIndex, IReadOnlyList cascadingParameters) - { - _directParamsEnumerator = new RenderTreeFrameParameterEnumerator(frames, ownerIndex); - _cascadingParameterEnumerator = new CascadingParameterEnumerator(cascadingParameters); - _isEnumeratingDirectParams = true; - } - - /// - /// Gets the current value of the enumerator. - /// - public ParameterValue Current => _isEnumeratingDirectParams - ? _directParamsEnumerator.Current - : _cascadingParameterEnumerator.Current; - - /// - /// Instructs the enumerator to move to the next value in the sequence. - /// - /// A flag to indicate whether or not there is a next value. - public bool MoveNext() - { - if (_isEnumeratingDirectParams) - { - if (_directParamsEnumerator.MoveNext()) - { - return true; - } - else - { - _isEnumeratingDirectParams = false; - } - } - - return _cascadingParameterEnumerator.MoveNext(); - } - } - - private struct RenderTreeFrameParameterEnumerator - { - private readonly RenderTreeFrame[] _frames; - private readonly int _ownerIndex; - private readonly int _ownerDescendantsEndIndexExcl; - private int _currentIndex; - private ParameterValue _current; - - internal RenderTreeFrameParameterEnumerator(RenderTreeFrame[] frames, int ownerIndex) - { - _frames = frames; - _ownerIndex = ownerIndex; - _ownerDescendantsEndIndexExcl = ownerIndex + _frames[ownerIndex].ElementSubtreeLength; - _currentIndex = ownerIndex; - _current = default; - } - - public ParameterValue Current => _current; - - public bool MoveNext() - { - // Stop iteration if you get to the end of the owner's descendants... - var nextIndex = _currentIndex + 1; - if (nextIndex == _ownerDescendantsEndIndexExcl) - { - return false; - } - - // ... or if you get to its first non-attribute descendant (because attributes - // are always before any other type of descendant) - if (_frames[nextIndex].FrameType != RenderTreeFrameType.Attribute) - { - return false; - } - - _currentIndex = nextIndex; - - ref var frame = ref _frames[_currentIndex]; - _current = new ParameterValue(frame.AttributeName, frame.AttributeValue, false); - - return true; - } - } - - private struct CascadingParameterEnumerator - { - private readonly IReadOnlyList _cascadingParameters; - private int _currentIndex; - private ParameterValue _current; - - public CascadingParameterEnumerator(IReadOnlyList cascadingParameters) - { - _cascadingParameters = cascadingParameters; - _currentIndex = -1; - _current = default; - } - - public ParameterValue Current => _current; - - public bool MoveNext() - { - // Bail out early if there are no cascading parameters - if (_cascadingParameters == null) - { - return false; - } - - var nextIndex = _currentIndex + 1; - if (nextIndex < _cascadingParameters.Count) - { - _currentIndex = nextIndex; - - var state = _cascadingParameters[_currentIndex]; - _current = new ParameterValue(state.LocalValueName, state.ValueSupplier.CurrentValue, true); - return true; - } - else - { - return false; - } - } - } - } -} diff --git a/src/Components/Components/src/PlatformInfo.cs b/src/Components/Components/src/PlatformInfo.cs deleted file mode 100644 index 81338cab58..0000000000 --- a/src/Components/Components/src/PlatformInfo.cs +++ /dev/null @@ -1,17 +0,0 @@ -// 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.Runtime.InteropServices; - -namespace Microsoft.AspNetCore.Components -{ - internal static class PlatformInfo - { - public static bool IsWebAssembly { get; } - - static PlatformInfo() - { - IsWebAssembly = RuntimeInformation.IsOSPlatform(OSPlatform.Create("WEBASSEMBLY")); - } - } -} diff --git a/src/Components/Components/src/Properties/AssemblyInfo.cs b/src/Components/Components/src/Properties/AssemblyInfo.cs deleted file mode 100644 index d5aa38e01d..0000000000 --- a/src/Components/Components/src/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.Runtime.CompilerServices; - -[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Blazor.Build.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] -[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Components.Authorization.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] -[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Components.Forms.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] -[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Components.Performance, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] -[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Components.Server.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] -[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Components.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] -[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Components.Web.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] diff --git a/src/Components/Components/src/Reflection/ComponentProperties.cs b/src/Components/Components/src/Reflection/ComponentProperties.cs deleted file mode 100644 index 0b85a66a84..0000000000 --- a/src/Components/Components/src/Reflection/ComponentProperties.cs +++ /dev/null @@ -1,288 +0,0 @@ -// 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.Collections.Concurrent; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Reflection; - -namespace Microsoft.AspNetCore.Components.Reflection -{ - internal static class ComponentProperties - { - private const BindingFlags _bindablePropertyFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.IgnoreCase; - - // Right now it's not possible for a component to define a Parameter and a Cascading Parameter with - // the same name. We don't give you a way to express this in code (would create duplicate properties), - // and we don't have the ability to represent it in our data structures. - private readonly static ConcurrentDictionary _cachedWritersByType - = new ConcurrentDictionary(); - - public static void SetProperties(in ParameterView parameters, object target) - { - if (target == null) - { - throw new ArgumentNullException(nameof(target)); - } - - var targetType = target.GetType(); - if (!_cachedWritersByType.TryGetValue(targetType, out var writers)) - { - writers = new WritersForType(targetType); - _cachedWritersByType[targetType] = writers; - } - - // The logic is split up for simplicity now that we have CaptureUnmatchedValues parameters. - if (writers.CaptureUnmatchedValuesWriter == null) - { - // Logic for components without a CaptureUnmatchedValues parameter - foreach (var parameter in parameters) - { - var parameterName = parameter.Name; - if (!writers.WritersByName.TryGetValue(parameterName, out var writer)) - { - // Case 1: There is nowhere to put this value. - ThrowForUnknownIncomingParameterName(targetType, parameterName); - throw null; // Unreachable - } - else if (writer.Cascading && !parameter.Cascading) - { - // We don't allow you to set a cascading parameter with a non-cascading value. Put another way: - // cascading parameters are not part of the public API of a component, so it's not reasonable - // for someone to set it directly. - // - // If we find a strong reason for this to work in the future we can reverse our decision since - // this throws today. - ThrowForSettingCascadingParameterWithNonCascadingValue(targetType, parameterName); - throw null; // Unreachable - } - else if (!writer.Cascading && parameter.Cascading) - { - // We're giving a more specific error here because trying to set a non-cascading parameter - // with a cascading value is likely deliberate (but not supported), or is a bug in our code. - ThrowForSettingParameterWithCascadingValue(targetType, parameterName); - throw null; // Unreachable - } - - SetProperty(target, writer, parameterName, parameter.Value); - } - } - else - { - // Logic with components with a CaptureUnmatchedValues parameter - var isCaptureUnmatchedValuesParameterSetExplicitly = false; - Dictionary unmatched = null; - foreach (var parameter in parameters) - { - var parameterName = parameter.Name; - if (string.Equals(parameterName, writers.CaptureUnmatchedValuesPropertyName, StringComparison.OrdinalIgnoreCase)) - { - isCaptureUnmatchedValuesParameterSetExplicitly = true; - } - - var isUnmatchedValue = !writers.WritersByName.TryGetValue(parameterName, out var writer); - - if ((isUnmatchedValue && parameter.Cascading) || (writer != null && !writer.Cascading && parameter.Cascading)) - { - // Don't allow an "extra" cascading value to be collected - or don't allow a non-cascading - // parameter to be set with a cascading value. - // - // This is likely a bug in our infrastructure or an attempt to deliberately do something unsupported. - ThrowForSettingParameterWithCascadingValue(targetType, parameterName); - throw null; // Unreachable - - } - else if (isUnmatchedValue || - - // Allow unmatched parameters to collide with the names of cascading parameters. This is - // valid because cascading parameter names are not part of the public API. There's no - // way for the user of a component to know what the names of cascading parameters - // are. - (writer.Cascading && !parameter.Cascading)) - { - unmatched ??= new Dictionary(StringComparer.OrdinalIgnoreCase); - unmatched[parameterName] = parameter.Value; - } - else - { - Debug.Assert(writer != null); - SetProperty(target, writer, parameterName, parameter.Value); - } - } - - if (unmatched != null && isCaptureUnmatchedValuesParameterSetExplicitly) - { - // This has to be an error because we want to allow users to set the CaptureUnmatchedValues - // parameter explicitly and .... - // 1. We don't ever want to mutate a value the user gives us. - // 2. We also don't want to implicitly copy a value the user gives us. - // - // Either one of those implementation choices would do something unexpected. - ThrowForCaptureUnmatchedValuesConflict(targetType, writers.CaptureUnmatchedValuesPropertyName, unmatched); - throw null; // Unreachable - } - else if (unmatched != null) - { - // We had some unmatched values, set the CaptureUnmatchedValues property - SetProperty(target, writers.CaptureUnmatchedValuesWriter, writers.CaptureUnmatchedValuesPropertyName, unmatched); - } - } - - static void SetProperty(object target, IPropertySetter writer, string parameterName, object value) - { - try - { - writer.SetValue(target, value); - } - catch (Exception ex) - { - throw new InvalidOperationException( - $"Unable to set property '{parameterName}' on object of " + - $"type '{target.GetType().FullName}'. The error was: {ex.Message}", ex); - } - } - } - - internal static IEnumerable GetCandidateBindableProperties(Type targetType) - => MemberAssignment.GetPropertiesIncludingInherited(targetType, _bindablePropertyFlags); - - private static void ThrowForUnknownIncomingParameterName(Type targetType, string parameterName) - { - // We know we're going to throw by this stage, so it doesn't matter that the following - // reflection code will be slow. We're just trying to help developers see what they did wrong. - var propertyInfo = targetType.GetProperty(parameterName, _bindablePropertyFlags); - if (propertyInfo != null) - { - if (!propertyInfo.IsDefined(typeof(ParameterAttribute)) && !propertyInfo.IsDefined(typeof(CascadingParameterAttribute))) - { - throw new InvalidOperationException( - $"Object of type '{targetType.FullName}' has a property matching the name '{parameterName}', " + - $"but it does not have [{nameof(ParameterAttribute)}] or [{nameof(CascadingParameterAttribute)}] applied."); - } - else - { - // This should not happen - throw new InvalidOperationException( - $"No writer was cached for the property '{propertyInfo.Name}' on type '{targetType.FullName}'."); - } - } - else - { - throw new InvalidOperationException( - $"Object of type '{targetType.FullName}' does not have a property " + - $"matching the name '{parameterName}'."); - } - } - - private static void ThrowForSettingCascadingParameterWithNonCascadingValue(Type targetType, string parameterName) - { - throw new InvalidOperationException( - $"Object of type '{targetType.FullName}' has a property matching the name '{parameterName}', " + - $"but it does not have [{nameof(ParameterAttribute)}] applied."); - } - - private static void ThrowForSettingParameterWithCascadingValue(Type targetType, string parameterName) - { - throw new InvalidOperationException( - $"The property '{parameterName}' on component type '{targetType.FullName}' cannot be set " + - $"using a cascading value."); - } - - private static void ThrowForCaptureUnmatchedValuesConflict(Type targetType, string parameterName, Dictionary unmatched) - { - throw new InvalidOperationException( - $"The property '{parameterName}' on component type '{targetType.FullName}' cannot be set explicitly " + - $"when also used to capture unmatched values. Unmatched values:" + Environment.NewLine + - string.Join(Environment.NewLine, unmatched.Keys.OrderBy(k => k))); - } - - private static void ThrowForMultipleCaptureUnmatchedValuesParameters(Type targetType) - { - // We don't care about perf here, we want to report an accurate and useful error. - var propertyNames = targetType - .GetProperties(_bindablePropertyFlags) - .Where(p => p.GetCustomAttribute()?.CaptureUnmatchedValues == true) - .Select(p => p.Name) - .OrderBy(p => p) - .ToArray(); - - throw new InvalidOperationException( - $"Multiple properties were found on component type '{targetType.FullName}' with " + - $"'{nameof(ParameterAttribute)}.{nameof(ParameterAttribute.CaptureUnmatchedValues)}'. Only a single property " + - $"per type can use '{nameof(ParameterAttribute)}.{nameof(ParameterAttribute.CaptureUnmatchedValues)}'. Properties:" + Environment.NewLine + - string.Join(Environment.NewLine, propertyNames)); - } - - private static void ThrowForInvalidCaptureUnmatchedValuesParameterType(Type targetType, PropertyInfo propertyInfo) - { - throw new InvalidOperationException( - $"The property '{propertyInfo.Name}' on component type '{targetType.FullName}' cannot be used " + - $"with '{nameof(ParameterAttribute)}.{nameof(ParameterAttribute.CaptureUnmatchedValues)}' because it has the wrong type. " + - $"The property must be assignable from 'Dictionary'."); - } - - private class WritersForType - { - public WritersForType(Type targetType) - { - WritersByName = new Dictionary(StringComparer.OrdinalIgnoreCase); - foreach (var propertyInfo in GetCandidateBindableProperties(targetType)) - { - var parameterAttribute = propertyInfo.GetCustomAttribute(); - var cascadingParameterAttribute = propertyInfo.GetCustomAttribute(); - var isParameter = parameterAttribute != null || cascadingParameterAttribute != null; - if (!isParameter) - { - continue; - } - - var propertyName = propertyInfo.Name; - if (parameterAttribute != null && (propertyInfo.SetMethod == null || !propertyInfo.SetMethod.IsPublic)) - { - throw new InvalidOperationException( - $"The type '{targetType.FullName}' declares a parameter matching the name '{propertyName}' that is not public. Parameters must be public."); - } - - var propertySetter = MemberAssignment.CreatePropertySetter(targetType, propertyInfo, cascading: cascadingParameterAttribute != null); - - if (WritersByName.ContainsKey(propertyName)) - { - throw new InvalidOperationException( - $"The type '{targetType.FullName}' declares more than one parameter matching the " + - $"name '{propertyName.ToLowerInvariant()}'. Parameter names are case-insensitive and must be unique."); - } - - WritersByName.Add(propertyName, propertySetter); - - if (parameterAttribute != null && parameterAttribute.CaptureUnmatchedValues) - { - // This is an "Extra" parameter. - // - // There should only be one of these. - if (CaptureUnmatchedValuesWriter != null) - { - ThrowForMultipleCaptureUnmatchedValuesParameters(targetType); - } - - // It must be able to hold a Dictionary since that's what we create. - if (!propertyInfo.PropertyType.IsAssignableFrom(typeof(Dictionary))) - { - ThrowForInvalidCaptureUnmatchedValuesParameterType(targetType, propertyInfo); - } - - CaptureUnmatchedValuesWriter = MemberAssignment.CreatePropertySetter(targetType, propertyInfo, cascading: false); - CaptureUnmatchedValuesPropertyName = propertyInfo.Name; - } - } - } - - public Dictionary WritersByName { get; } - - public IPropertySetter CaptureUnmatchedValuesWriter { get; } - - public string CaptureUnmatchedValuesPropertyName { get; } - } - } -} diff --git a/src/Components/Components/src/Reflection/IPropertySetter.cs b/src/Components/Components/src/Reflection/IPropertySetter.cs deleted file mode 100644 index d6a60e2395..0000000000 --- a/src/Components/Components/src/Reflection/IPropertySetter.cs +++ /dev/null @@ -1,12 +0,0 @@ -// 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. - -namespace Microsoft.AspNetCore.Components.Reflection -{ - internal interface IPropertySetter - { - bool Cascading { get; } - - void SetValue(object target, object value); - } -} diff --git a/src/Components/Components/src/Reflection/MemberAssignment.cs b/src/Components/Components/src/Reflection/MemberAssignment.cs deleted file mode 100644 index ab0cf6b1e7..0000000000 --- a/src/Components/Components/src/Reflection/MemberAssignment.cs +++ /dev/null @@ -1,87 +0,0 @@ -// 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.Collections.Generic; -using System.Linq; -using System.Reflection; - -namespace Microsoft.AspNetCore.Components.Reflection -{ - internal class MemberAssignment - { - public static IEnumerable GetPropertiesIncludingInherited( - Type type, BindingFlags bindingFlags) - { - var dictionary = new Dictionary>(); - - while (type != null) - { - var properties = type.GetProperties(bindingFlags) - .Where(prop => prop.DeclaringType == type); - foreach (var property in properties) - { - if (!dictionary.TryGetValue(property.Name, out var others)) - { - others = new List(); - dictionary.Add(property.Name, others); - } - - if (others.Any(other => other.GetMethod?.GetBaseDefinition() == property.GetMethod?.GetBaseDefinition())) - { - // This is an inheritance case. We can safely ignore the value of property since - // we have seen a more derived value. - continue; - } - - others.Add(property); - } - - type = type.BaseType; - } - - return dictionary.Values.SelectMany(p => p); - } - - public static IPropertySetter CreatePropertySetter(Type targetType, PropertyInfo property, bool cascading) - { - if (property.SetMethod == null) - { - throw new InvalidOperationException($"Cannot provide a value for property " + - $"'{property.Name}' on type '{targetType.FullName}' because the property " + - $"has no setter."); - } - - return (IPropertySetter)Activator.CreateInstance( - typeof(PropertySetter<,>).MakeGenericType(targetType, property.PropertyType), - property.SetMethod, - cascading); - } - - class PropertySetter : IPropertySetter - { - private readonly Action _setterDelegate; - - public PropertySetter(MethodInfo setMethod, bool cascading) - { - _setterDelegate = (Action)Delegate.CreateDelegate( - typeof(Action), setMethod); - Cascading = cascading; - } - - public bool Cascading { get; } - - public void SetValue(object target, object value) - { - if (value == null) - { - _setterDelegate((TTarget)target, default); - } - else - { - _setterDelegate((TTarget)target, (TValue)value); - } - } - } - } -} diff --git a/src/Components/Components/src/RenderFragment.cs b/src/Components/Components/src/RenderFragment.cs deleted file mode 100644 index cf27ad2cc4..0000000000 --- a/src/Components/Components/src/RenderFragment.cs +++ /dev/null @@ -1,22 +0,0 @@ -// 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.AspNetCore.Components.Rendering; - -namespace Microsoft.AspNetCore.Components -{ - /// - /// Represents a segment of UI content, implemented as a delegate that - /// writes the content to a . - /// - /// The to which the content should be written. - public delegate void RenderFragment(RenderTreeBuilder builder); - - /// - /// Represents a segment of UI content for an object of type , implemented as - /// a function that returns a . - /// - /// The type of object. - /// The value used to build the content. - public delegate RenderFragment RenderFragment(TValue value); -} diff --git a/src/Components/Components/src/RenderHandle.cs b/src/Components/Components/src/RenderHandle.cs deleted file mode 100644 index fb646feeee..0000000000 --- a/src/Components/Components/src/RenderHandle.cs +++ /dev/null @@ -1,65 +0,0 @@ -// 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 Microsoft.AspNetCore.Components.RenderTree; - -namespace Microsoft.AspNetCore.Components -{ - /// - /// Allows a component to interact with its renderer. - /// - public readonly struct RenderHandle - { - private readonly Renderer _renderer; - private readonly int _componentId; - - internal RenderHandle(Renderer renderer, int componentId) - { - _renderer = renderer ?? throw new System.ArgumentNullException(nameof(renderer)); - _componentId = componentId; - } - - /// - /// Gets the associated with the component. - /// - public Dispatcher Dispatcher - { - get - { - if (_renderer == null) - { - ThrowNotInitialized(); - } - - return _renderer.Dispatcher; - } - } - - /// - /// Gets a value that indicates whether the has been - /// initialized and is ready to use. - /// - public bool IsInitialized - => _renderer != null; - - /// - /// Notifies the renderer that the component should be rendered. - /// - /// The content that should be rendered. - public void Render(RenderFragment renderFragment) - { - if (_renderer == null) - { - ThrowNotInitialized(); - } - - _renderer.AddToRenderQueue(_componentId, renderFragment); - } - - private static void ThrowNotInitialized() - { - throw new InvalidOperationException("The render handle is not yet assigned."); - } - } -} diff --git a/src/Components/Components/src/RenderTree/ArrayBuilderExtensions.cs b/src/Components/Components/src/RenderTree/ArrayBuilderExtensions.cs deleted file mode 100644 index 2252000716..0000000000 --- a/src/Components/Components/src/RenderTree/ArrayBuilderExtensions.cs +++ /dev/null @@ -1,31 +0,0 @@ -// 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; - -#if IGNITOR -namespace Ignitor -#else -namespace Microsoft.AspNetCore.Components.RenderTree -#endif -{ - internal static class ArrayBuilderExtensions - { - /// - /// Produces an structure describing the current contents. - /// - /// The . - public static ArrayRange ToRange(this ArrayBuilder builder) - => new ArrayRange(builder.Buffer, builder.Count); - - /// - /// Produces an structure describing the selected contents. - /// - /// The - /// The index of the first item in the segment. - /// One plus the index of the last item in the segment. - /// The . - public static ArrayBuilderSegment ToSegment(this ArrayBuilder builder, int fromIndexInclusive, int toIndexExclusive) - => new ArrayBuilderSegment(builder, fromIndexInclusive, toIndexExclusive - fromIndexInclusive); - } -} diff --git a/src/Components/Components/src/RenderTree/ArrayBuilderSegment.cs b/src/Components/Components/src/RenderTree/ArrayBuilderSegment.cs deleted file mode 100644 index 4820e2f5fd..0000000000 --- a/src/Components/Components/src/RenderTree/ArrayBuilderSegment.cs +++ /dev/null @@ -1,67 +0,0 @@ -// 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.Collections; -using System.Collections.Generic; - -#if IGNITOR -namespace Ignitor -#else -namespace Microsoft.AspNetCore.Components.RenderTree -#endif -{ - /// - /// Types in the Microsoft.AspNetCore.Components.RenderTree are not recommended for use outside - /// of the Blazor framework. These types will change in future release. - /// - /// The type of the elements in the array - // - // Represents a range of elements within an instance of . - public readonly struct ArrayBuilderSegment : IEnumerable - { - // The following fields are memory mapped to the WASM client. Do not re-order or use auto-properties. - private readonly ArrayBuilder _builder; - private readonly int _offset; - private readonly int _count; - - internal ArrayBuilderSegment(ArrayBuilder builder, int offset, int count) - { - _builder = builder; - _offset = offset; - _count = count; - } - - /// - /// Gets the current underlying array holding the segment's elements. - /// - public T[] Array => _builder?.Buffer; - - /// - /// Gets the offset into the underlying array holding the segment's elements. - /// - public int Offset => _offset; - - /// - /// Gets the number of items in the segment. - /// - public int Count => _count; - - /// - /// Gets the specified item from the segment. - /// - /// The index into the segment. - /// The array entry at the specified index within the segment. - public T this[int index] - => _builder.Buffer[_offset + index]; - - IEnumerator IEnumerable.GetEnumerator() - => ((IEnumerable)new ArraySegment(_builder.Buffer, _offset, _count)).GetEnumerator(); - - IEnumerator IEnumerable.GetEnumerator() - => ((IEnumerable)new ArraySegment(_builder.Buffer, _offset, _count)).GetEnumerator(); - - // TODO: If this assembly later moves to netstandard2.1, consider adding a public - // GetEnumerator method that returns ArraySegment.Enumerator to avoid boxing. - } -} diff --git a/src/Components/Components/src/RenderTree/ArrayRange.cs b/src/Components/Components/src/RenderTree/ArrayRange.cs deleted file mode 100644 index a980a92246..0000000000 --- a/src/Components/Components/src/RenderTree/ArrayRange.cs +++ /dev/null @@ -1,51 +0,0 @@ -// 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. - -#if IGNITOR -namespace Ignitor -#else -namespace Microsoft.AspNetCore.Components.RenderTree -#endif -{ - /// - /// Types in the Microsoft.AspNetCore.Components.RenderTree are not recommended for use outside - /// of the Blazor framework. These types will change in future release. - /// - /// - // - // Represents a range of elements in an array that are in use. - public readonly struct ArrayRange - { - /// - /// Gets the underlying array instance. - /// - public readonly T[] Array; - - /// - /// Gets the number of items in the array that are considered to be in use. - /// - public readonly int Count; - - /// - /// Constructs an instance of . - /// - /// The array. - /// The number of items in the array that are in use. - public ArrayRange(T[] array, int count) - { - Array = array; - Count = count; - } - - /// - /// Creates a shallow clone of the instance. - /// - /// - public ArrayRange Clone() - { - var buffer = new T[Count]; - System.Array.Copy(Array, buffer, Count); - return new ArrayRange(buffer, Count); - } - } -} diff --git a/src/Components/Components/src/RenderTree/EventFieldInfo.cs b/src/Components/Components/src/RenderTree/EventFieldInfo.cs deleted file mode 100644 index 129057ff73..0000000000 --- a/src/Components/Components/src/RenderTree/EventFieldInfo.cs +++ /dev/null @@ -1,26 +0,0 @@ -// 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. - -namespace Microsoft.AspNetCore.Components.RenderTree -{ - /// - /// Types in the Microsoft.AspNetCore.Components.RenderTree are not recommended for use outside - /// of the Blazor framework. These types will change in a future release. - /// - // - // Information supplied with an event notification that can be used to update an existing - // render tree to match the latest UI state when a form field has mutated. To determine - // which field has been mutated, the renderer matches it based on the event handler ID. - public class EventFieldInfo - { - /// - /// Identifies the component whose render tree contains the affected form field. - /// - public int ComponentId { get; set; } - - /// - /// Specifies the form field's new value. - /// - public object FieldValue { get; set; } - } -} diff --git a/src/Components/Components/src/RenderTree/RenderBatch.cs b/src/Components/Components/src/RenderTree/RenderBatch.cs deleted file mode 100644 index 55f3c02629..0000000000 --- a/src/Components/Components/src/RenderTree/RenderBatch.cs +++ /dev/null @@ -1,52 +0,0 @@ -// 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. - -#if IGNITOR -namespace Ignitor -#else -namespace Microsoft.AspNetCore.Components.RenderTree -#endif -{ - /// - /// Types in the Microsoft.AspNetCore.Components.RenderTree are not recommended for use outside - /// of the Blazor framework. These types will change in a future release. - /// - // - // Describes a set of UI changes. - public readonly struct RenderBatch - { - /// - /// Gets the changes to components that were added or updated. - /// - public ArrayRange UpdatedComponents { get; } - - /// - /// Gets render frames that may be referenced by entries in . - /// For example, edit entries of type - /// will point to an entry in this array to specify the subtree to be prepended. - /// - public ArrayRange ReferenceFrames { get; } - - /// - /// Gets the IDs of the components that were disposed. - /// - public ArrayRange DisposedComponentIDs { get; } - - /// - /// Gets the IDs of the event handlers that were disposed. - /// - public ArrayRange DisposedEventHandlerIDs { get; } - - internal RenderBatch( - ArrayRange updatedComponents, - ArrayRange referenceFrames, - ArrayRange disposedComponentIDs, - ArrayRange disposedEventHandlerIDs) - { - UpdatedComponents = updatedComponents; - ReferenceFrames = referenceFrames; - DisposedComponentIDs = disposedComponentIDs; - DisposedEventHandlerIDs = disposedEventHandlerIDs; - } - } -} diff --git a/src/Components/Components/src/RenderTree/RenderTreeDiff.cs b/src/Components/Components/src/RenderTree/RenderTreeDiff.cs deleted file mode 100644 index 4947029ab2..0000000000 --- a/src/Components/Components/src/RenderTree/RenderTreeDiff.cs +++ /dev/null @@ -1,36 +0,0 @@ -// 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. - -#if IGNITOR -namespace Ignitor -#else -namespace Microsoft.AspNetCore.Components.RenderTree -#endif -{ - /// - /// Types in the Microsoft.AspNetCore.Components.RenderTree are not recommended for use outside - /// of the Blazor framework. These types will change in future release. - /// - // - // Describes changes to a component's render tree between successive renders. - public readonly struct RenderTreeDiff - { - /// - /// Gets the ID of the component. - /// - public readonly int ComponentId; - - /// - /// Gets the changes to the render tree since a previous state. - /// - public readonly ArrayBuilderSegment Edits; - - internal RenderTreeDiff( - int componentId, - ArrayBuilderSegment entries) - { - ComponentId = componentId; - Edits = entries; - } - } -} diff --git a/src/Components/Components/src/RenderTree/RenderTreeDiffBuilder.cs b/src/Components/Components/src/RenderTree/RenderTreeDiffBuilder.cs deleted file mode 100644 index 11f5540f4c..0000000000 --- a/src/Components/Components/src/RenderTree/RenderTreeDiffBuilder.cs +++ /dev/null @@ -1,998 +0,0 @@ -// 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.Collections.Generic; -using Microsoft.AspNetCore.Components.Rendering; - -namespace Microsoft.AspNetCore.Components.RenderTree -{ - internal static class RenderTreeDiffBuilder - { - enum DiffAction { Match, Insert, Delete } - - // We use int.MinValue to signal this special case because (1) it would never be used by - // the Razor compiler or by accident in developer code, and (2) we know it will always - // hit the "old < new" code path during diffing so we only have to check for it in one place. - public const int SystemAddedAttributeSequenceNumber = int.MinValue; - - public static RenderTreeDiff ComputeDiff( - Renderer renderer, - RenderBatchBuilder batchBuilder, - int componentId, - ArrayRange oldTree, - ArrayRange newTree) - { - var editsBuffer = batchBuilder.EditsBuffer; - var editsBufferStartLength = editsBuffer.Count; - - var diffContext = new DiffContext(renderer, batchBuilder, componentId, oldTree.Array, newTree.Array); - AppendDiffEntriesForRange(ref diffContext, 0, oldTree.Count, 0, newTree.Count); - - var editsSegment = editsBuffer.ToSegment(editsBufferStartLength, editsBuffer.Count); - return new RenderTreeDiff(componentId, editsSegment); - } - - public static void DisposeFrames(RenderBatchBuilder batchBuilder, ArrayRange frames) - => DisposeFramesInRange(batchBuilder, frames.Array, 0, frames.Count); - - private static void AppendDiffEntriesForRange( - ref DiffContext diffContext, - int oldStartIndex, int oldEndIndexExcl, - int newStartIndex, int newEndIndexExcl) - { - // This is deliberately a very large method. Parts of it could be factored out - // into other private methods, but doing so comes at a consequential perf cost, - // because it involves so much parameter passing. You can think of the code here - // as being several private methods (delimited by #region) pre-inlined. - // - // A naive "extract methods"-type refactoring will worsen perf by about 10%. So, - // if you plan to refactor this, be sure to benchmark the old and new versions - // on Mono WebAssembly. - - var origOldStartIndex = oldStartIndex; - var origNewStartIndex = newStartIndex; - var hasMoreOld = oldEndIndexExcl > oldStartIndex; - var hasMoreNew = newEndIndexExcl > newStartIndex; - var prevOldSeq = -1; - var prevNewSeq = -1; - var oldTree = diffContext.OldTree; - var newTree = diffContext.NewTree; - var matchWithNewTreeIndex = -1; // Only used when action == DiffAction.Match - Dictionary keyedItemInfos = null; - - try - { - while (hasMoreOld || hasMoreNew) - { - DiffAction action; - - #region "Read keys and sequence numbers" - int oldSeq, newSeq; - object oldKey, newKey; - if (hasMoreOld) - { - ref var oldFrame = ref oldTree[oldStartIndex]; - oldSeq = oldFrame.Sequence; - oldKey = KeyValue(ref oldFrame); - } - else - { - oldSeq = int.MaxValue; - oldKey = null; - } - - if (hasMoreNew) - { - ref var newFrame = ref newTree[newStartIndex]; - newSeq = newFrame.Sequence; - newKey = KeyValue(ref newFrame); - } - else - { - newSeq = int.MaxValue; - newKey = null; - } - #endregion - - // If there's a key on either side, prefer matching by key not sequence - if (oldKey != null || newKey != null) - { - #region "Get diff action by matching on key" - // Regardless of whether these two keys match, since you are using keys, we want to validate at this point that there are no clashes - // so ensure we've built the dictionary that will be used for lookups if any don't match - keyedItemInfos ??= BuildKeyToInfoLookup(diffContext, origOldStartIndex, oldEndIndexExcl, origNewStartIndex, newEndIndexExcl); - - if (Equals(oldKey, newKey)) - { - // Keys match - action = DiffAction.Match; - matchWithNewTreeIndex = newStartIndex; - } - else - { - // Keys don't match - var oldKeyItemInfo = oldKey != null ? keyedItemInfos[oldKey] : new KeyedItemInfo(-1, -1); - var newKeyItemInfo = newKey != null ? keyedItemInfos[newKey] : new KeyedItemInfo(-1, -1); - var oldKeyIsInNewTree = oldKeyItemInfo.NewIndex >= 0; - var newKeyIsInOldTree = newKeyItemInfo.OldIndex >= 0; - - // If either key is not in the other tree, we can handle it as an insert or a delete - // on this iteration. We're only forced to use the move logic that's not the case - // (i.e., both keys are in both trees) - if (oldKeyIsInNewTree && newKeyIsInOldTree) - { - // It's a move - // Since the recipient of the diff script already has the old frame (the one with oldKey) - // at the current siblingIndex, recurse into oldKey and update its descendants in place. - // We re-order the frames afterwards. - action = DiffAction.Match; - matchWithNewTreeIndex = oldKeyItemInfo.NewIndex; - - // Track the post-edit sibling indices of the moved items - // Since diffContext.SiblingIndex only increases, we can be sure the values we - // write at this point will remain correct, because there won't be any further - // insertions/deletions at smaller sibling indices. - keyedItemInfos[oldKey] = oldKeyItemInfo.WithOldSiblingIndex(diffContext.SiblingIndex); - keyedItemInfos[newKey] = newKeyItemInfo.WithNewSiblingIndex(diffContext.SiblingIndex); - } - else if (!hasMoreNew) - { - // If we've run out of new items, we must be looking at just an old item, so delete it - action = DiffAction.Delete; - } - else - { - // It's an insertion or a deletion, or both - // If the new key is in both trees, but the old key isn't, then the old item was deleted - // Otherwise, it's either an insertion or *both* insertion+deletion, so pick insertion and get the deletion on the next iteration if needed - action = newKeyIsInOldTree ? DiffAction.Delete : DiffAction.Insert; - } - } - #endregion - } - else - { - #region "Get diff action by matching on sequence number" - // Neither side is keyed, so match by sequence number - if (oldSeq == newSeq) - { - // Sequences match - action = DiffAction.Match; - matchWithNewTreeIndex = newStartIndex; - } - else - { - // Sequences don't match - var oldLoopedBack = oldSeq <= prevOldSeq; - var newLoopedBack = newSeq <= prevNewSeq; - if (oldLoopedBack == newLoopedBack) - { - // Both sequences are proceeding through the same loop block, so do a simple - // preordered merge join (picking from whichever side brings us closer to being - // back in sync) - action = newSeq < oldSeq ? DiffAction.Insert : DiffAction.Delete; - - if (oldLoopedBack) - { - // If both old and new have now looped back, we must reset their 'looped back' - // tracker so we can treat them as proceeding through the same loop block - prevOldSeq = -1; - prevNewSeq = -1; - } - } - else if (oldLoopedBack) - { - // Old sequence looped back but new one didn't - // The new sequence either has some extra trailing elements in the current loop block - // which we should insert, or omits some old trailing loop blocks which we should delete - // TODO: Find a way of not recomputing this next flag on every iteration - var newLoopsBackLater = false; - for (var testIndex = newStartIndex + 1; testIndex < newEndIndexExcl; testIndex++) - { - if (newTree[testIndex].Sequence < newSeq) - { - newLoopsBackLater = true; - break; - } - } - - // If the new sequence loops back later to an earlier point than this, - // then we know it's part of the existing loop block (so should be inserted). - // If not, then it's unrelated to the previous loop block (so we should treat - // the old items as trailing loop blocks to be removed). - action = newLoopsBackLater ? DiffAction.Insert : DiffAction.Delete; - } - else - { - // New sequence looped back but old one didn't - // The old sequence either has some extra trailing elements in the current loop block - // which we should delete, or the new sequence has extra trailing loop blocks which we - // should insert - // TODO: Find a way of not recomputing this next flag on every iteration - var oldLoopsBackLater = false; - for (var testIndex = oldStartIndex + 1; testIndex < oldEndIndexExcl; testIndex++) - { - if (oldTree[testIndex].Sequence < oldSeq) - { - oldLoopsBackLater = true; - break; - } - } - - // If the old sequence loops back later to an earlier point than this, - // then we know it's part of the existing loop block (so should be removed). - // If not, then it's unrelated to the previous loop block (so we should treat - // the new items as trailing loop blocks to be inserted). - action = oldLoopsBackLater ? DiffAction.Delete : DiffAction.Insert; - } - } - #endregion - } - - #region "Apply diff action" - switch (action) - { - case DiffAction.Match: - AppendDiffEntriesForFramesWithSameSequence(ref diffContext, oldStartIndex, matchWithNewTreeIndex); - oldStartIndex = NextSiblingIndex(oldTree[oldStartIndex], oldStartIndex); - newStartIndex = NextSiblingIndex(newTree[newStartIndex], newStartIndex); - hasMoreOld = oldEndIndexExcl > oldStartIndex; - hasMoreNew = newEndIndexExcl > newStartIndex; - prevOldSeq = oldSeq; - prevNewSeq = newSeq; - break; - case DiffAction.Insert: - InsertNewFrame(ref diffContext, newStartIndex); - newStartIndex = NextSiblingIndex(newTree[newStartIndex], newStartIndex); - hasMoreNew = newEndIndexExcl > newStartIndex; - prevNewSeq = newSeq; - break; - case DiffAction.Delete: - RemoveOldFrame(ref diffContext, oldStartIndex); - oldStartIndex = NextSiblingIndex(oldTree[oldStartIndex], oldStartIndex); - hasMoreOld = oldEndIndexExcl > oldStartIndex; - prevOldSeq = oldSeq; - break; - } - #endregion - } - - #region "Write permutations list" - if (keyedItemInfos != null) - { - var hasPermutations = false; - foreach (var keyValuePair in keyedItemInfos) - { - var value = keyValuePair.Value; - if (value.OldSiblingIndex >= 0 && value.NewSiblingIndex >= 0) - { - // This item moved - hasPermutations = true; - diffContext.Edits.Append( - RenderTreeEdit.PermutationListEntry(value.OldSiblingIndex, value.NewSiblingIndex)); - } - } - - if (hasPermutations) - { - // It's much easier for the recipient to handle if we're explicit about - // when the list is finished - diffContext.Edits.Append(RenderTreeEdit.PermutationListEnd()); - } - } - #endregion - } - finally - { - if (keyedItemInfos != null) - { - keyedItemInfos.Clear(); - diffContext.KeyedItemInfoDictionaryPool.Return(keyedItemInfos); - } - } - } - - private static Dictionary BuildKeyToInfoLookup(DiffContext diffContext, int oldStartIndex, int oldEndIndexExcl, int newStartIndex, int newEndIndexExcl) - { - var result = diffContext.KeyedItemInfoDictionaryPool.Get(); - var oldTree = diffContext.OldTree; - var newTree = diffContext.NewTree; - - while (oldStartIndex < oldEndIndexExcl) - { - ref var frame = ref oldTree[oldStartIndex]; - var key = KeyValue(ref frame); - if (key != null) - { - if (result.ContainsKey(key)) - { - ThrowExceptionForDuplicateKey(key); - } - - result[key] = new KeyedItemInfo(oldStartIndex, -1); - } - - oldStartIndex = NextSiblingIndex(frame, oldStartIndex); - } - - while (newStartIndex < newEndIndexExcl) - { - ref var frame = ref newTree[newStartIndex]; - var key = KeyValue(ref frame); - if (key != null) - { - if (!result.TryGetValue(key, out var existingEntry)) - { - result[key] = new KeyedItemInfo(-1, newStartIndex); - } - else - { - if (existingEntry.NewIndex >= 0) - { - ThrowExceptionForDuplicateKey(key); - } - - result[key] = new KeyedItemInfo(existingEntry.OldIndex, newStartIndex); - } - } - - newStartIndex = NextSiblingIndex(frame, newStartIndex); - } - - return result; - } - - private static void ThrowExceptionForDuplicateKey(object key) - { - throw new InvalidOperationException($"More than one sibling has the same key value, '{key}'. Key values must be unique."); - } - - private static object KeyValue(ref RenderTreeFrame frame) - { - switch (frame.FrameType) - { - case RenderTreeFrameType.Element: - return frame.ElementKey; - case RenderTreeFrameType.Component: - return frame.ComponentKey; - default: - return null; - } - } - - // Handles the diff for attribute nodes only - this invariant is enforced by the caller. - // - // The diff for attributes is different because we allow attributes to appear in any order. - // Put another way, the attributes list of an element or component is *conceptually* - // unordered. This is a case where we can produce a more minimal diff by avoiding - // non-meaningful reorderings of attributes. - private static void AppendAttributeDiffEntriesForRange( - ref DiffContext diffContext, - int oldStartIndex, int oldEndIndexExcl, - int newStartIndex, int newEndIndexExcl) - { - // The overhead of the dictionary used by AppendAttributeDiffEntriesForRangeSlow is - // significant, so we want to try and do a merge-join if possible, but fall back to - // a hash-join if not. We'll do a merge join until we hit a case we can't handle and - // then fall back to the slow path. - // - // Also since duplicate attributes are not legal, we don't need to care about loops or - // the more complicated scenarios handled by AppendDiffEntriesForRange. - // - // We also assume that we won't see an attribute occur with different sequence numbers - // in the old and new sequences. It will be handled correct, but will generate a suboptimal - // diff. - var hasMoreOld = oldEndIndexExcl > oldStartIndex; - var hasMoreNew = newEndIndexExcl > newStartIndex; - var oldTree = diffContext.OldTree; - var newTree = diffContext.NewTree; - - while (hasMoreOld || hasMoreNew) - { - var oldSeq = hasMoreOld ? oldTree[oldStartIndex].Sequence : int.MaxValue; - var newSeq = hasMoreNew ? newTree[newStartIndex].Sequence : int.MaxValue; - var oldAttributeName = oldTree[oldStartIndex].AttributeName; - var newAttributeName = newTree[newStartIndex].AttributeName; - - if (oldSeq == newSeq && - string.Equals(oldAttributeName, newAttributeName, StringComparison.Ordinal)) - { - // These two attributes have the same sequence and name. Keep merging. - AppendDiffEntriesForAttributeFrame(ref diffContext, oldStartIndex, newStartIndex); - - oldStartIndex++; - newStartIndex++; - hasMoreOld = oldEndIndexExcl > oldStartIndex; - hasMoreNew = newEndIndexExcl > newStartIndex; - } - else if (oldSeq < newSeq) - { - if (oldSeq == SystemAddedAttributeSequenceNumber) - { - // This special sequence number means that we can't rely on the sequence numbers - // for matching and are forced to fall back on the dictionary-based join in order - // to produce an optimal diff. If we didn't we'd likely produce a diff that removes - // and then re-adds the same attribute. - // We use the special sequence number to signal it because it adds almost no cost - // to check for it only in this one case. - AppendAttributeDiffEntriesForRangeSlow( - ref diffContext, - oldStartIndex, oldEndIndexExcl, - newStartIndex, newEndIndexExcl); - return; - } - - // An attribute was removed compared to the old sequence. - RemoveOldFrame(ref diffContext, oldStartIndex); - - oldStartIndex = NextSiblingIndex(oldTree[oldStartIndex], oldStartIndex); - hasMoreOld = oldEndIndexExcl > oldStartIndex; - } - else if (oldSeq > newSeq) - { - // An attribute was added compared to the new sequence. - InsertNewFrame(ref diffContext, newStartIndex); - - newStartIndex = NextSiblingIndex(newTree[newStartIndex], newStartIndex); - hasMoreNew = newEndIndexExcl > newStartIndex; - } - else - { - // These two attributes have the same sequence and different names. This is - // a failure case for merge-join, fall back to the slow path. - AppendAttributeDiffEntriesForRangeSlow( - ref diffContext, - oldStartIndex, oldEndIndexExcl, - newStartIndex, newEndIndexExcl); - return; - } - } - } - - private static void AppendAttributeDiffEntriesForRangeSlow( - ref DiffContext diffContext, - int oldStartIndex, int oldEndIndexExcl, - int newStartIndex, int newEndIndexExcl) - { - var oldTree = diffContext.OldTree; - var newTree = diffContext.NewTree; - - // Slow version of AppendAttributeDiffEntriesForRange that uses a dictionary. - // Algorithm: - // - // 1. iterate through the 'new' tree and add all attributes to the attributes set - // 2. iterate through the 'old' tree, removing matching attributes from set, and diffing - // 3. iterate through the remaining attributes in the set and add them - for (var i = newStartIndex; i < newEndIndexExcl; i++) - { - diffContext.AttributeDiffSet[newTree[i].AttributeName] = i; - } - - for (var i = oldStartIndex; i < oldEndIndexExcl; i++) - { - var oldName = oldTree[i].AttributeName; - if (diffContext.AttributeDiffSet.TryGetValue(oldName, out var matchIndex)) - { - // Has a match in the new tree, look for a diff - AppendDiffEntriesForAttributeFrame(ref diffContext, i, matchIndex); - diffContext.AttributeDiffSet.Remove(oldName); - } - else - { - // No match in the new tree, remove old attribute - RemoveOldFrame(ref diffContext, i); - } - } - - foreach (var kvp in diffContext.AttributeDiffSet) - { - // No match in the old tree - InsertNewFrame(ref diffContext, kvp.Value); - } - - // We should have processed any additions at this point. Reset for the next batch. - diffContext.AttributeDiffSet.Clear(); - } - - private static void UpdateRetainedChildComponent( - ref DiffContext diffContext, - int oldComponentIndex, - int newComponentIndex) - { - var oldTree = diffContext.OldTree; - var newTree = diffContext.NewTree; - ref var oldComponentFrame = ref oldTree[oldComponentIndex]; - ref var newComponentFrame = ref newTree[newComponentIndex]; - var componentState = oldComponentFrame.ComponentState; - - // Preserve the actual componentInstance - newComponentFrame = newComponentFrame.WithComponent(componentState); - - // As an important rendering optimization, we want to skip parameter update - // notifications if we know for sure they haven't changed/mutated. The - // "MayHaveChangedSince" logic is conservative, in that it returns true if - // any parameter is of a type we don't know is immutable. In this case - // we call SetParameters and it's up to the recipient to implement - // whatever change-detection logic they want. Currently we only supply the new - // set of parameters and assume the recipient has enough info to do whatever - // comparisons it wants with the old values. Later we could choose to pass the - // old parameter values if we wanted. By default, components always rerender - // after any SetParameters call, which is safe but now always optimal for perf. - var oldParameters = new ParameterView(ParameterViewLifetime.Unbound, oldTree, oldComponentIndex); - var newParametersLifetime = new ParameterViewLifetime(diffContext.BatchBuilder); - var newParameters = new ParameterView(newParametersLifetime, newTree, newComponentIndex); - if (!newParameters.DefinitelyEquals(oldParameters)) - { - componentState.SetDirectParameters(newParameters); - } - } - - private static int NextSiblingIndex(in RenderTreeFrame frame, int frameIndex) - { - switch (frame.FrameType) - { - case RenderTreeFrameType.Component: - return frameIndex + frame.ComponentSubtreeLength; - case RenderTreeFrameType.Element: - return frameIndex + frame.ElementSubtreeLength; - case RenderTreeFrameType.Region: - return frameIndex + frame.RegionSubtreeLength; - default: - return frameIndex + 1; - } - } - - private static void AppendDiffEntriesForFramesWithSameSequence( - ref DiffContext diffContext, - int oldFrameIndex, - int newFrameIndex) - { - var oldTree = diffContext.OldTree; - var newTree = diffContext.NewTree; - ref var oldFrame = ref oldTree[oldFrameIndex]; - ref var newFrame = ref newTree[newFrameIndex]; - - // This can't happen for sequence-matched frames from .razor components, but it can happen if you write your - // builder logic manually or if two dissimilar frames matched by key. Treat as completely unrelated. - var newFrameType = newFrame.FrameType; - if (oldFrame.FrameType != newFrameType) - { - InsertNewFrame(ref diffContext, newFrameIndex); - RemoveOldFrame(ref diffContext, oldFrameIndex); - return; - } - - // We can assume that the old and new frames are of the same type, because they correspond - // to the same sequence number (and if not, the behaviour is undefined). - // TODO: Consider supporting dissimilar types at same sequence for custom IComponent implementations. - // It should only be a matter of calling RemoveOldFrame+InsertNewFrame - switch (newFrameType) - { - case RenderTreeFrameType.Text: - { - var oldText = oldFrame.TextContent; - var newText = newFrame.TextContent; - if (!string.Equals(oldText, newText, StringComparison.Ordinal)) - { - var referenceFrameIndex = diffContext.ReferenceFrames.Append(newFrame); - diffContext.Edits.Append(RenderTreeEdit.UpdateText(diffContext.SiblingIndex, referenceFrameIndex)); - } - diffContext.SiblingIndex++; - break; - } - - case RenderTreeFrameType.Markup: - { - var oldMarkup = oldFrame.MarkupContent; - var newMarkup = newFrame.MarkupContent; - if (!string.Equals(oldMarkup, newMarkup, StringComparison.Ordinal)) - { - var referenceFrameIndex = diffContext.ReferenceFrames.Append(newFrame); - diffContext.Edits.Append(RenderTreeEdit.UpdateMarkup(diffContext.SiblingIndex, referenceFrameIndex)); - } - diffContext.SiblingIndex++; - break; - } - - case RenderTreeFrameType.Element: - { - var oldElementName = oldFrame.ElementName; - var newElementName = newFrame.ElementName; - if (string.Equals(oldElementName, newElementName, StringComparison.Ordinal)) - { - var oldFrameAttributesEndIndexExcl = GetAttributesEndIndexExclusive(oldTree, oldFrameIndex); - var newFrameAttributesEndIndexExcl = GetAttributesEndIndexExclusive(newTree, newFrameIndex); - - // Diff the attributes - AppendAttributeDiffEntriesForRange( - ref diffContext, - oldFrameIndex + 1, oldFrameAttributesEndIndexExcl, - newFrameIndex + 1, newFrameAttributesEndIndexExcl); - - // Diff the children - var oldFrameChildrenEndIndexExcl = oldFrameIndex + oldFrame.ElementSubtreeLength; - var newFrameChildrenEndIndexExcl = newFrameIndex + newFrame.ElementSubtreeLength; - var hasChildrenToProcess = - oldFrameChildrenEndIndexExcl > oldFrameAttributesEndIndexExcl || - newFrameChildrenEndIndexExcl > newFrameAttributesEndIndexExcl; - if (hasChildrenToProcess) - { - diffContext.Edits.Append(RenderTreeEdit.StepIn(diffContext.SiblingIndex)); - var prevSiblingIndex = diffContext.SiblingIndex; - diffContext.SiblingIndex = 0; - AppendDiffEntriesForRange( - ref diffContext, - oldFrameAttributesEndIndexExcl, oldFrameChildrenEndIndexExcl, - newFrameAttributesEndIndexExcl, newFrameChildrenEndIndexExcl); - AppendStepOut(ref diffContext); - diffContext.SiblingIndex = prevSiblingIndex + 1; - } - else - { - diffContext.SiblingIndex++; - } - } - else - { - // Elements with different names are treated as completely unrelated - RemoveOldFrame(ref diffContext, oldFrameIndex); - InsertNewFrame(ref diffContext, newFrameIndex); - } - break; - } - - case RenderTreeFrameType.Region: - { - AppendDiffEntriesForRange( - ref diffContext, - oldFrameIndex + 1, oldFrameIndex + oldFrame.RegionSubtreeLength, - newFrameIndex + 1, newFrameIndex + newFrame.RegionSubtreeLength); - break; - } - - case RenderTreeFrameType.Component: - { - if (oldFrame.ComponentType == newFrame.ComponentType) - { - UpdateRetainedChildComponent( - ref diffContext, - oldFrameIndex, - newFrameIndex); - diffContext.SiblingIndex++; - } - else - { - // Child components of different types are treated as completely unrelated - RemoveOldFrame(ref diffContext, oldFrameIndex); - InsertNewFrame(ref diffContext, newFrameIndex); - } - break; - } - - case RenderTreeFrameType.ElementReferenceCapture: - { - // We could preserve the ElementReferenceCaptureId from the old frame to the new frame, - // and even call newFrame.ElementReferenceCaptureAction(id) each time in case it wants - // to do something different with the ID. However there's no known use case for - // that, so presently the rule is that for any given element, the reference - // capture action is only invoked once. - break; - } - - // We don't handle attributes here, they have their own diff logic. - // See AppendDiffEntriesForAttributeFrame - default: - throw new NotImplementedException($"Encountered unsupported frame type during diffing: {newTree[newFrameIndex].FrameType}"); - } - } - - // This should only be called for attributes that have the same name. This is an - // invariant maintained by the callers. - private static void AppendDiffEntriesForAttributeFrame( - ref DiffContext diffContext, - int oldFrameIndex, - int newFrameIndex) - { - var oldTree = diffContext.OldTree; - var newTree = diffContext.NewTree; - ref var oldFrame = ref oldTree[oldFrameIndex]; - ref var newFrame = ref newTree[newFrameIndex]; - - // Using Equals to account for string comparisons, nulls, etc. - var valueChanged = !Equals(oldFrame.AttributeValue, newFrame.AttributeValue); - if (valueChanged) - { - InitializeNewAttributeFrame(ref diffContext, ref newFrame); - var referenceFrameIndex = diffContext.ReferenceFrames.Append(newFrame); - diffContext.Edits.Append(RenderTreeEdit.SetAttribute(diffContext.SiblingIndex, referenceFrameIndex)); - - // If we're replacing an old event handler ID with a new one, register the old one for disposal, - // plus keep track of the old->new chain until the old one is fully disposed - if (oldFrame.AttributeEventHandlerId > 0) - { - diffContext.Renderer.TrackReplacedEventHandlerId(oldFrame.AttributeEventHandlerId, newFrame.AttributeEventHandlerId); - diffContext.BatchBuilder.DisposedEventHandlerIds.Append(oldFrame.AttributeEventHandlerId); - } - } - else if (oldFrame.AttributeEventHandlerId > 0) - { - // Retain the event handler ID by copying the old frame over the new frame. - // this will prevent us from needing to dispose the old event handler - // since it was unchanged. - newFrame = oldFrame; - } - } - - private static void InsertNewFrame(ref DiffContext diffContext, int newFrameIndex) - { - var newTree = diffContext.NewTree; - ref var newFrame = ref newTree[newFrameIndex]; - switch (newFrame.FrameType) - { - case RenderTreeFrameType.Attribute: - { - InitializeNewAttributeFrame(ref diffContext, ref newFrame); - var referenceFrameIndex = diffContext.ReferenceFrames.Append(newFrame); - diffContext.Edits.Append(RenderTreeEdit.SetAttribute(diffContext.SiblingIndex, referenceFrameIndex)); - break; - } - case RenderTreeFrameType.Component: - case RenderTreeFrameType.Element: - { - InitializeNewSubtree(ref diffContext, newFrameIndex); - var referenceFrameIndex = diffContext.ReferenceFrames.Append(newTree, newFrameIndex, newFrame.ElementSubtreeLength); - diffContext.Edits.Append(RenderTreeEdit.PrependFrame(diffContext.SiblingIndex, referenceFrameIndex)); - diffContext.SiblingIndex++; - break; - } - case RenderTreeFrameType.Region: - { - var regionChildFrameIndex = newFrameIndex + 1; - var regionChildFrameEndIndexExcl = newFrameIndex + newFrame.RegionSubtreeLength; - while (regionChildFrameIndex < regionChildFrameEndIndexExcl) - { - InsertNewFrame(ref diffContext, regionChildFrameIndex); - regionChildFrameIndex = NextSiblingIndex(newTree[regionChildFrameIndex], regionChildFrameIndex); - } - break; - } - case RenderTreeFrameType.Text: - case RenderTreeFrameType.Markup: - { - var referenceFrameIndex = diffContext.ReferenceFrames.Append(newFrame); - diffContext.Edits.Append(RenderTreeEdit.PrependFrame(diffContext.SiblingIndex, referenceFrameIndex)); - diffContext.SiblingIndex++; - break; - } - case RenderTreeFrameType.ElementReferenceCapture: - { - InitializeNewElementReferenceCaptureFrame(ref diffContext, ref newFrame); - break; - } - case RenderTreeFrameType.ComponentReferenceCapture: - { - InitializeNewComponentReferenceCaptureFrame(ref diffContext, ref newFrame); - break; - } - default: - throw new NotImplementedException($"Unexpected frame type during {nameof(InsertNewFrame)}: {newFrame.FrameType}"); - } - } - - private static void RemoveOldFrame(ref DiffContext diffContext, int oldFrameIndex) - { - var oldTree = diffContext.OldTree; - ref var oldFrame = ref oldTree[oldFrameIndex]; - switch (oldFrame.FrameType) - { - case RenderTreeFrameType.Attribute: - { - diffContext.Edits.Append(RenderTreeEdit.RemoveAttribute(diffContext.SiblingIndex, oldFrame.AttributeName)); - if (oldFrame.AttributeEventHandlerId > 0) - { - diffContext.BatchBuilder.DisposedEventHandlerIds.Append(oldFrame.AttributeEventHandlerId); - } - break; - } - case RenderTreeFrameType.Component: - case RenderTreeFrameType.Element: - { - var endIndexExcl = oldFrameIndex + oldFrame.ElementSubtreeLength; - DisposeFramesInRange(diffContext.BatchBuilder, oldTree, oldFrameIndex, endIndexExcl); - diffContext.Edits.Append(RenderTreeEdit.RemoveFrame(diffContext.SiblingIndex)); - break; - } - case RenderTreeFrameType.Region: - { - var regionChildFrameIndex = oldFrameIndex + 1; - var regionChildFrameEndIndexExcl = oldFrameIndex + oldFrame.RegionSubtreeLength; - while (regionChildFrameIndex < regionChildFrameEndIndexExcl) - { - RemoveOldFrame(ref diffContext, regionChildFrameIndex); - regionChildFrameIndex = NextSiblingIndex(oldTree[regionChildFrameIndex], regionChildFrameIndex); - } - break; - } - case RenderTreeFrameType.Text: - case RenderTreeFrameType.Markup: - { - diffContext.Edits.Append(RenderTreeEdit.RemoveFrame(diffContext.SiblingIndex)); - break; - } - default: - throw new NotImplementedException($"Unexpected frame type during {nameof(RemoveOldFrame)}: {oldFrame.FrameType}"); - } - } - - private static int GetAttributesEndIndexExclusive(RenderTreeFrame[] tree, int rootIndex) - { - var descendantsEndIndexExcl = rootIndex + tree[rootIndex].ElementSubtreeLength; - var index = rootIndex + 1; - for (; index < descendantsEndIndexExcl; index++) - { - if (tree[index].FrameType != RenderTreeFrameType.Attribute) - { - break; - } - } - - return index; - } - - private static void AppendStepOut(ref DiffContext diffContext) - { - // If the preceding frame is a StepIn, then the StepOut cancels it out - var previousIndex = diffContext.Edits.Count - 1; - if (previousIndex >= 0 && diffContext.Edits.Buffer[previousIndex].Type == RenderTreeEditType.StepIn) - { - diffContext.Edits.RemoveLast(); - } - else - { - diffContext.Edits.Append(RenderTreeEdit.StepOut()); - } - } - - private static void InitializeNewSubtree(ref DiffContext diffContext, int frameIndex) - { - var frames = diffContext.NewTree; - var endIndexExcl = frameIndex + frames[frameIndex].ElementSubtreeLength; - for (var i = frameIndex; i < endIndexExcl; i++) - { - ref var frame = ref frames[i]; - switch (frame.FrameType) - { - case RenderTreeFrameType.Component: - InitializeNewComponentFrame(ref diffContext, i); - break; - case RenderTreeFrameType.Attribute: - InitializeNewAttributeFrame(ref diffContext, ref frame); - break; - case RenderTreeFrameType.ElementReferenceCapture: - InitializeNewElementReferenceCaptureFrame(ref diffContext, ref frame); - break; - case RenderTreeFrameType.ComponentReferenceCapture: - InitializeNewComponentReferenceCaptureFrame(ref diffContext, ref frame); - break; - } - } - } - - private static void InitializeNewComponentFrame(ref DiffContext diffContext, int frameIndex) - { - var frames = diffContext.NewTree; - ref var frame = ref frames[frameIndex]; - - if (frame.ComponentState != null) - { - throw new InvalidOperationException($"Child component already exists during {nameof(InitializeNewComponentFrame)}"); - } - - var parentComponentId = diffContext.ComponentId; - diffContext.Renderer.InstantiateChildComponentOnFrame(ref frame, parentComponentId); - var childComponentState = frame.ComponentState; - - // Set initial parameters - var initialParametersLifetime = new ParameterViewLifetime(diffContext.BatchBuilder); - var initialParameters = new ParameterView(initialParametersLifetime, frames, frameIndex); - childComponentState.SetDirectParameters(initialParameters); - } - - private static void InitializeNewAttributeFrame(ref DiffContext diffContext, ref RenderTreeFrame newFrame) - { - // Any attribute with an event handler id will be callable via DOM events - // - // We're following a simple heuristic here that's reflected in the ts runtime - // based on the common usage of attributes for DOM events. - if ((newFrame.AttributeValue is MulticastDelegate || newFrame.AttributeValue is EventCallback) && - newFrame.AttributeName.Length >= 3 && - newFrame.AttributeName.StartsWith("on")) - { - diffContext.Renderer.AssignEventHandlerId(ref newFrame); - } - } - - private static void InitializeNewElementReferenceCaptureFrame(ref DiffContext diffContext, ref RenderTreeFrame newFrame) - { - var newElementReference = ElementReference.CreateWithUniqueId(); - newFrame = newFrame.WithElementReferenceCaptureId(newElementReference.Id); - newFrame.ElementReferenceCaptureAction(newElementReference); - } - - private static void InitializeNewComponentReferenceCaptureFrame(ref DiffContext diffContext, ref RenderTreeFrame newFrame) - { - ref var parentFrame = ref diffContext.NewTree[newFrame.ComponentReferenceCaptureParentFrameIndex]; - if (parentFrame.FrameType != RenderTreeFrameType.Component) - { - // Should never happen, but will help with diagnosis if it does - throw new InvalidOperationException($"{nameof(RenderTreeFrameType.ComponentReferenceCapture)} frame references invalid parent index."); - } - - var componentInstance = parentFrame.Component; - if (componentInstance == null) - { - // Should never happen, but will help with diagnosis if it does - throw new InvalidOperationException($"Trying to initialize {nameof(RenderTreeFrameType.ComponentReferenceCapture)} frame before parent component was assigned."); - } - - newFrame.ComponentReferenceCaptureAction(componentInstance); - } - - private static void DisposeFramesInRange(RenderBatchBuilder batchBuilder, RenderTreeFrame[] frames, int startIndex, int endIndexExcl) - { - for (var i = startIndex; i < endIndexExcl; i++) - { - ref var frame = ref frames[i]; - if (frame.FrameType == RenderTreeFrameType.Component && frame.ComponentState != null) - { - batchBuilder.ComponentDisposalQueue.Enqueue(frame.ComponentId); - } - else if (frame.FrameType == RenderTreeFrameType.Attribute && frame.AttributeEventHandlerId > 0) - { - batchBuilder.DisposedEventHandlerIds.Append(frame.AttributeEventHandlerId); - } - } - } - - /// - /// Exists only so that the various methods in this class can call each other without - /// constantly building up long lists of parameters. Is private to this class, so the - /// fact that it's a mutable struct is manageable. - /// - /// Always pass by ref to avoid copying, and because the 'SiblingIndex' is mutable. - /// - private struct DiffContext - { - public readonly Renderer Renderer; - public readonly RenderBatchBuilder BatchBuilder; - public readonly RenderTreeFrame[] OldTree; - public readonly RenderTreeFrame[] NewTree; - public readonly ArrayBuilder Edits; - public readonly ArrayBuilder ReferenceFrames; - public readonly Dictionary AttributeDiffSet; - public readonly StackObjectPool> KeyedItemInfoDictionaryPool; - public readonly int ComponentId; - public int SiblingIndex; - - public DiffContext( - Renderer renderer, - RenderBatchBuilder batchBuilder, - int componentId, - RenderTreeFrame[] oldTree, - RenderTreeFrame[] newTree) - { - Renderer = renderer; - BatchBuilder = batchBuilder; - ComponentId = componentId; - OldTree = oldTree; - NewTree = newTree; - Edits = batchBuilder.EditsBuffer; - ReferenceFrames = batchBuilder.ReferenceFramesBuffer; - AttributeDiffSet = batchBuilder.AttributeDiffSet; - KeyedItemInfoDictionaryPool = batchBuilder.KeyedItemInfoDictionaryPool; - SiblingIndex = 0; - } - } - } -} diff --git a/src/Components/Components/src/RenderTree/RenderTreeEdit.cs b/src/Components/Components/src/RenderTree/RenderTreeEdit.cs deleted file mode 100644 index 93b1dd9da6..0000000000 --- a/src/Components/Components/src/RenderTree/RenderTreeEdit.cs +++ /dev/null @@ -1,111 +0,0 @@ -// 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.Runtime.InteropServices; - -#if IGNITOR -namespace Ignitor -#else -namespace Microsoft.AspNetCore.Components.RenderTree -#endif -{ - /// - /// Types in the Microsoft.AspNetCore.Components.RenderTree are not recommended for use outside - /// of the Blazor framework. These types will change in future release. - /// - // - // Represents a single edit operation on a component's render tree. - [StructLayout(LayoutKind.Explicit)] - public readonly struct RenderTreeEdit - { - /// - /// Gets the type of the edit operation. - /// - [FieldOffset(0)] public readonly RenderTreeEditType Type; - - /// - /// Gets the index of the sibling frame that the edit relates to. - /// - [FieldOffset(4)] public readonly int SiblingIndex; - - /// - /// Gets the index of related data in an associated render frames array. For example, if the - /// value is , gets the - /// index of the new frame data in an associated render tree. - /// - [FieldOffset(8)] public readonly int ReferenceFrameIndex; - - /// - /// If the value is , - /// gets the sibling index to which the frame should be moved. - /// - // NOTE: Other code relies on the assumption that ReferenceFrameIndex and - // MoveToSiblingIndex share a memory slot. If you change this, be sure to - // update affected usages of ReferenceFrameIndex. - [FieldOffset(8)] public readonly int MoveToSiblingIndex; - - /// - /// If the value is , - /// gets the name of the attribute that is being removed. - /// - [FieldOffset(16)] public readonly string RemovedAttributeName; - - private RenderTreeEdit(RenderTreeEditType type) : this() - { - Type = type; - } - - private RenderTreeEdit(RenderTreeEditType type, int siblingIndex) : this() - { - Type = type; - SiblingIndex = siblingIndex; - } - - private RenderTreeEdit(RenderTreeEditType type, int siblingIndex, int referenceFrameOrMoveToSiblingIndex) : this() - { - Type = type; - SiblingIndex = siblingIndex; - - // MoveToSiblingIndex is stored in the same slot as ReferenceFrameIndex, - // so assigning to either one is equivalent - ReferenceFrameIndex = referenceFrameOrMoveToSiblingIndex; - } - - private RenderTreeEdit(RenderTreeEditType type, int siblingIndex, string removedAttributeName) : this() - { - Type = type; - SiblingIndex = siblingIndex; - RemovedAttributeName = removedAttributeName; - } - - internal static RenderTreeEdit RemoveFrame(int siblingIndex) - => new RenderTreeEdit(RenderTreeEditType.RemoveFrame, siblingIndex); - - internal static RenderTreeEdit PrependFrame(int siblingIndex, int referenceFrameIndex) - => new RenderTreeEdit(RenderTreeEditType.PrependFrame, siblingIndex, referenceFrameIndex); - - internal static RenderTreeEdit UpdateText(int siblingIndex, int referenceFrameIndex) - => new RenderTreeEdit(RenderTreeEditType.UpdateText, siblingIndex, referenceFrameIndex); - - internal static RenderTreeEdit UpdateMarkup(int siblingIndex, int referenceFrameIndex) - => new RenderTreeEdit(RenderTreeEditType.UpdateMarkup, siblingIndex, referenceFrameIndex); - - internal static RenderTreeEdit SetAttribute(int siblingIndex, int referenceFrameIndex) - => new RenderTreeEdit(RenderTreeEditType.SetAttribute, siblingIndex, referenceFrameIndex); - - internal static RenderTreeEdit RemoveAttribute(int siblingIndex, string name) - => new RenderTreeEdit(RenderTreeEditType.RemoveAttribute, siblingIndex, name); - - internal static RenderTreeEdit StepIn(int siblingIndex) - => new RenderTreeEdit(RenderTreeEditType.StepIn, siblingIndex); - - internal static RenderTreeEdit StepOut() - => new RenderTreeEdit(RenderTreeEditType.StepOut); - - internal static RenderTreeEdit PermutationListEntry(int fromSiblingIndex, int toSiblingIndex) - => new RenderTreeEdit(RenderTreeEditType.PermutationListEntry, fromSiblingIndex, toSiblingIndex); - - internal static RenderTreeEdit PermutationListEnd() - => new RenderTreeEdit(RenderTreeEditType.PermutationListEnd); - } -} diff --git a/src/Components/Components/src/RenderTree/RenderTreeEditType.cs b/src/Components/Components/src/RenderTree/RenderTreeEditType.cs deleted file mode 100644 index f3d48172fb..0000000000 --- a/src/Components/Components/src/RenderTree/RenderTreeEditType.cs +++ /dev/null @@ -1,75 +0,0 @@ -// 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. - -#if IGNITOR -namespace Ignitor -#else -namespace Microsoft.AspNetCore.Components.RenderTree -#endif -{ - /// - /// Types in the Microsoft.AspNetCore.Components.RenderTree are not recommended for use outside - /// of the Blazor framework. These types will change in future release. - /// - // - //Describes the type of a render tree edit operation. - public enum RenderTreeEditType: int - { - /// - /// Indicates that a new frame should be inserted before the specified tree frame. - /// - PrependFrame = 1, - - /// - /// Indicates that the specified tree frame should be removed. - /// - RemoveFrame = 2, - - /// - /// Indicates that an attribute value should be applied to the specified frame. - /// This may be a change to an existing attribute, or the addition of a new attribute. - /// - SetAttribute = 3, - - /// - /// Indicates that a named attribute should be removed from the specified frame. - /// - RemoveAttribute = 4, - - /// - /// Indicates that the text content of the specified frame (which must be a text frame) - /// should be updated. - /// - UpdateText = 5, - - /// - /// Indicates that the edit position should move inside the specified frame. - /// - StepIn = 6, - - /// - /// Indicates that there are no further edit operations on the current frame, and the - /// edit position should move back to the parent frame. - /// - StepOut = 7, - - /// - /// Indicates that the markup content of the specified frame (which must be a markup frame) - /// should be updated. - /// - UpdateMarkup = 8, - - /// - /// An entry in a sparse permutation list. That is, a list of old indices with - /// corresponding new indices, which altogether describe a valid permutation of - /// the children at the current edit position. - /// - PermutationListEntry = 9, - - /// - /// Indicates that the preceding series of entries - /// is now complete. - /// - PermutationListEnd = 10, - } -} diff --git a/src/Components/Components/src/RenderTree/RenderTreeFrame.cs b/src/Components/Components/src/RenderTree/RenderTreeFrame.cs deleted file mode 100644 index c9a358c698..0000000000 --- a/src/Components/Components/src/RenderTree/RenderTreeFrame.cs +++ /dev/null @@ -1,406 +0,0 @@ -// 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.Runtime.InteropServices; -#if !IGNITOR -using Microsoft.AspNetCore.Components.Rendering; -#endif - -#if IGNITOR -namespace Ignitor -#else -namespace Microsoft.AspNetCore.Components.RenderTree -#endif -{ - /// - /// Types in the Microsoft.AspNetCore.Components.RenderTree are not recommended for use outside - /// of the Blazor framework. These types will change in future release. - /// - // - // Represents an entry in a tree of user interface (UI) items. - [StructLayout(LayoutKind.Explicit, Pack = 4)] - public readonly struct RenderTreeFrame - { - // Note that the struct layout has to be valid in both 32-bit and 64-bit runtime platforms, - // which means that all reference-type fields need to take up 8 bytes (except for the last - // one, which will be sized as either 4 or 8 bytes depending on the runtime platform). - - // Although each frame type uses the slots for different purposes, the runtime does not - // allow reference type slots to overlap with each other or with value-type slots. - // Here's the current layout: - // - // Offset Type - // ------ ---- - // 0-3 Int32 (sequence number) - // 4-5 Int16 (frame type) - // 6-15 Value types (usage varies by frame type) - // 16-23 Reference type (usage varies by frame type) - // 24-31 Reference type (usage varies by frame type) - // 32-39 Reference type (usage varies by frame type) - // - // On Mono WebAssembly, because it's 32-bit, the final slot occupies bytes 32-35, - // so the struct length is only 36. - - // -------------------------------------------------------------------------------- - // Common - // -------------------------------------------------------------------------------- - - /// - /// Gets the sequence number of the frame. Sequence numbers indicate the relative source - /// positions of the instructions that inserted the frames. Sequence numbers are only - /// comparable within the same sequence (typically, the same source method). - /// - [FieldOffset(0)] public readonly int Sequence; - - /// - /// Describes the type of this frame. - /// - [FieldOffset(4)] public readonly RenderTreeFrameType FrameType; - - // -------------------------------------------------------------------------------- - // RenderTreeFrameType.Element - // -------------------------------------------------------------------------------- - - /// - /// If the property equals - /// gets the number of frames in the subtree for which this frame is the root. - /// The value is zero if the frame has not yet been closed. - /// - [FieldOffset(8)] public readonly int ElementSubtreeLength; - - /// - /// If the property equals , - /// gets a name representing the type of the element. Otherwise, the value is undefined. - /// - [FieldOffset(16)] public readonly string ElementName; - - /// - /// If the property equals , - /// gets the element's diffing key, or null if none was specified. - /// - [FieldOffset(24)] public readonly object ElementKey; - - // -------------------------------------------------------------------------------- - // RenderTreeFrameType.Text - // -------------------------------------------------------------------------------- - - /// - /// If the property equals , - /// gets the content of the text frame. Otherwise, the value is undefined. - /// - [FieldOffset(16)] public readonly string TextContent; - - // -------------------------------------------------------------------------------- - // RenderTreeFrameType.Attribute - // -------------------------------------------------------------------------------- - - /// - /// If the property equals - /// gets the ID of the corresponding event handler, if any. - /// - [FieldOffset(8)] public readonly ulong AttributeEventHandlerId; - - /// - /// If the property equals , - /// gets the attribute name. Otherwise, the value is undefined. - /// - [FieldOffset(16)] public readonly string AttributeName; - - /// - /// If the property equals , - /// gets the attribute value. Otherwise, the value is undefined. - /// - [FieldOffset(24)] public readonly object AttributeValue; - - /// - /// If the property equals , - /// and the attribute represents an event handler, gets the name of another attribute whose value - /// can be updated to represent the UI state prior to executing the event handler. This is - /// primarily used in two-way bindings. - /// - [FieldOffset(32)] public readonly string AttributeEventUpdatesAttributeName; - - // -------------------------------------------------------------------------------- - // RenderTreeFrameType.Component - // -------------------------------------------------------------------------------- - - /// - /// If the property equals - /// gets the number of frames in the subtree for which this frame is the root. - /// The value is zero if the frame has not yet been closed. - /// - [FieldOffset(8)] public readonly int ComponentSubtreeLength; - - /// - /// If the property equals , - /// gets the child component instance identifier. - /// - [FieldOffset(12)] public readonly int ComponentId; - - /// - /// If the property equals , - /// gets the type of the child component. - /// - [FieldOffset(16)] public readonly Type ComponentType; - - /// - /// If the property equals , - /// gets the child component state object. Otherwise, the value is undefined. - /// - [FieldOffset(24)] internal readonly ComponentState ComponentState; - - /// - /// If the property equals , - /// gets the component's diffing key, or null if none was specified. - /// - [FieldOffset(32)] public readonly object ComponentKey; - - /// - /// If the property equals , - /// gets the child component instance. Otherwise, the value is undefined. - /// - public IComponent Component => ComponentState?.Component; - - // -------------------------------------------------------------------------------- - // RenderTreeFrameType.Region - // -------------------------------------------------------------------------------- - - /// - /// If the property equals - /// gets the number of frames in the subtree for which this frame is the root. - /// The value is zero if the frame has not yet been closed. - /// - [FieldOffset(8)] public readonly int RegionSubtreeLength; - - // -------------------------------------------------------------------------------- - // RenderTreeFrameType.ElementReferenceCapture - // -------------------------------------------------------------------------------- - - /// - /// If the property equals , - /// gets the ID of the reference capture. Otherwise, the value is undefined. - /// - [FieldOffset(16)] public readonly string ElementReferenceCaptureId; - - /// - /// If the property equals , - /// gets the action that writes the reference to its target. Otherwise, the value is undefined. - /// - [FieldOffset(24)] public readonly Action ElementReferenceCaptureAction; - - // -------------------------------------------------------------------------------- - // RenderTreeFrameType.ComponentReferenceCapture - // -------------------------------------------------------------------------------- - - /// - /// If the property equals , - /// gets the index of the parent frame representing the component being captured. Otherwise, the value is undefined. - /// WARNING: This index can only be used in the context of the frame's original render tree. If the frame is - /// copied elsewhere, such as to the ReferenceFrames buffer of a RenderTreeDiff, then the index will - /// not relate to entries in that other buffer. - /// Currently there's no scenario where this matters, but if there was, we could change all of the subtree - /// initialization logic in RenderTreeDiffBuilder to walk the frames hierarchically, then it would know - /// the parent index at the point where it wants to initialize the ComponentReferenceCapture frame. - /// - [FieldOffset(8)] public readonly int ComponentReferenceCaptureParentFrameIndex; - - /// - /// If the property equals , - /// gets the action that writes the reference to its target. Otherwise, the value is undefined. - /// - [FieldOffset(16)] public readonly Action ComponentReferenceCaptureAction; - - // -------------------------------------------------------------------------------- - // RenderTreeFrameType.Markup - // -------------------------------------------------------------------------------- - - /// - /// If the property equals , - /// gets the content of the markup frame. Otherwise, the value is undefined. - /// - [FieldOffset(16)] public readonly string MarkupContent; - - // Element constructor - private RenderTreeFrame(int sequence, int elementSubtreeLength, string elementName, object elementKey) - : this() - { - Sequence = sequence; - FrameType = RenderTreeFrameType.Element; - ElementSubtreeLength = elementSubtreeLength; - ElementName = elementName; - ElementKey = elementKey; - } - - // Component constructor - private RenderTreeFrame(int sequence, int componentSubtreeLength, Type componentType, ComponentState componentState, object componentKey) - : this() - { - Sequence = sequence; - FrameType = RenderTreeFrameType.Component; - ComponentSubtreeLength = componentSubtreeLength; - ComponentType = componentType; - ComponentKey = componentKey; - - if (componentState != null) - { - ComponentState = componentState; - ComponentId = componentState.ComponentId; - } - } - - // Region constructor - private RenderTreeFrame(int sequence, int regionSubtreeLength) - : this() - { - Sequence = sequence; - FrameType = RenderTreeFrameType.Region; - RegionSubtreeLength = regionSubtreeLength; - } - - // Text/markup constructor - private RenderTreeFrame(int sequence, bool isMarkup, string textOrMarkup) - : this() - { - Sequence = sequence; - if (isMarkup) - { - FrameType = RenderTreeFrameType.Markup; - MarkupContent = textOrMarkup; - } - else - { - FrameType = RenderTreeFrameType.Text; - TextContent = textOrMarkup; - } - } - - // Attribute constructor - private RenderTreeFrame(int sequence, string attributeName, object attributeValue, ulong attributeEventHandlerId, string attributeEventUpdatesAttributeName) - : this() - { - FrameType = RenderTreeFrameType.Attribute; - Sequence = sequence; - AttributeName = attributeName; - AttributeValue = attributeValue; - AttributeEventHandlerId = attributeEventHandlerId; - AttributeEventUpdatesAttributeName = attributeEventUpdatesAttributeName; - } - - // Element reference capture constructor - private RenderTreeFrame(int sequence, Action elementReferenceCaptureAction, string elementReferenceCaptureId) - : this() - { - FrameType = RenderTreeFrameType.ElementReferenceCapture; - Sequence = sequence; - ElementReferenceCaptureAction = elementReferenceCaptureAction; - ElementReferenceCaptureId = elementReferenceCaptureId; - } - - // Component reference capture constructor - private RenderTreeFrame(int sequence, Action componentReferenceCaptureAction, int parentFrameIndex) - : this() - { - FrameType = RenderTreeFrameType.ComponentReferenceCapture; - Sequence = sequence; - ComponentReferenceCaptureAction = componentReferenceCaptureAction; - ComponentReferenceCaptureParentFrameIndex = parentFrameIndex; - } - - internal static RenderTreeFrame Element(int sequence, string elementName) - => new RenderTreeFrame(sequence, elementSubtreeLength: 0, elementName, null); - - internal static RenderTreeFrame Text(int sequence, string textContent) - => new RenderTreeFrame(sequence, isMarkup: false, textOrMarkup: textContent); - - internal static RenderTreeFrame Markup(int sequence, string markupContent) - => new RenderTreeFrame(sequence, isMarkup: true, textOrMarkup: markupContent); - - internal static RenderTreeFrame Attribute(int sequence, string name, object value) - => new RenderTreeFrame(sequence, attributeName: name, attributeValue: value, attributeEventHandlerId: 0, attributeEventUpdatesAttributeName: null); - - internal static RenderTreeFrame ChildComponent(int sequence, Type componentType) - => new RenderTreeFrame(sequence, componentSubtreeLength: 0, componentType, null, null); - - internal static RenderTreeFrame PlaceholderChildComponentWithSubtreeLength(int subtreeLength) - => new RenderTreeFrame(0, componentSubtreeLength: subtreeLength, typeof(IComponent), null, null); - - internal static RenderTreeFrame Region(int sequence) - => new RenderTreeFrame(sequence, regionSubtreeLength: 0); - - internal static RenderTreeFrame ElementReferenceCapture(int sequence, Action elementReferenceCaptureAction) - => new RenderTreeFrame(sequence, elementReferenceCaptureAction: elementReferenceCaptureAction, elementReferenceCaptureId: null); - - internal static RenderTreeFrame ComponentReferenceCapture(int sequence, Action componentReferenceCaptureAction, int parentFrameIndex) - => new RenderTreeFrame(sequence, componentReferenceCaptureAction: componentReferenceCaptureAction, parentFrameIndex: parentFrameIndex); - - internal RenderTreeFrame WithElementSubtreeLength(int elementSubtreeLength) - => new RenderTreeFrame(Sequence, elementSubtreeLength: elementSubtreeLength, ElementName, ElementKey); - - internal RenderTreeFrame WithComponentSubtreeLength(int componentSubtreeLength) - => new RenderTreeFrame(Sequence, componentSubtreeLength: componentSubtreeLength, ComponentType, ComponentState, ComponentKey); - - internal RenderTreeFrame WithAttributeSequence(int sequence) - => new RenderTreeFrame(sequence, attributeName: AttributeName, AttributeValue, AttributeEventHandlerId, AttributeEventUpdatesAttributeName); - - internal RenderTreeFrame WithComponent(ComponentState componentState) - => new RenderTreeFrame(Sequence, componentSubtreeLength: ComponentSubtreeLength, ComponentType, componentState, ComponentKey); - - internal RenderTreeFrame WithAttributeEventHandlerId(ulong eventHandlerId) - => new RenderTreeFrame(Sequence, attributeName: AttributeName, AttributeValue, eventHandlerId, AttributeEventUpdatesAttributeName); - - internal RenderTreeFrame WithAttributeValue(object attributeValue) - => new RenderTreeFrame(Sequence, attributeName: AttributeName, attributeValue, AttributeEventHandlerId, AttributeEventUpdatesAttributeName); - - internal RenderTreeFrame WithAttributeEventUpdatesAttributeName(string attributeUpdatesAttributeName) - => new RenderTreeFrame(Sequence, attributeName: AttributeName, AttributeValue, AttributeEventHandlerId, attributeUpdatesAttributeName); - - internal RenderTreeFrame WithRegionSubtreeLength(int regionSubtreeLength) - => new RenderTreeFrame(Sequence, regionSubtreeLength: regionSubtreeLength); - - internal RenderTreeFrame WithElementReferenceCaptureId(string elementReferenceCaptureId) - => new RenderTreeFrame(Sequence, elementReferenceCaptureAction: ElementReferenceCaptureAction, elementReferenceCaptureId); - - internal RenderTreeFrame WithElementKey(object elementKey) - => new RenderTreeFrame(Sequence, elementSubtreeLength: ElementSubtreeLength, ElementName, elementKey); - - internal RenderTreeFrame WithComponentKey(object componentKey) - => new RenderTreeFrame(Sequence, componentSubtreeLength: ComponentSubtreeLength, ComponentType, ComponentState, componentKey); - - /// - // Just to be nice for debugging and unit tests. - public override string ToString() - { - switch (FrameType) - { - case RenderTreeFrameType.Attribute: - return $"Attribute: (seq={Sequence}, id={AttributeEventHandlerId}) '{AttributeName}'='{AttributeValue}'"; - - case RenderTreeFrameType.Component: - return $"Component: (seq={Sequence}, key={ComponentKey ?? "(none)"}, len={ComponentSubtreeLength}) {ComponentType}"; - - case RenderTreeFrameType.Element: - return $"Element: (seq={Sequence}, key={ElementKey ?? "(none)"}, len={ElementSubtreeLength}) {ElementName}"; - - case RenderTreeFrameType.Region: - return $"Region: (seq={Sequence}, len={RegionSubtreeLength})"; - - case RenderTreeFrameType.Text: - return $"Text: (seq={Sequence}, len=n/a) {EscapeNewlines(TextContent)}"; - - case RenderTreeFrameType.Markup: - return $"Markup: (seq={Sequence}, len=n/a) {EscapeNewlines(TextContent)}"; - - case RenderTreeFrameType.ElementReferenceCapture: - return $"ElementReferenceCapture: (seq={Sequence}, len=n/a) {ElementReferenceCaptureAction}"; - } - - return base.ToString(); - } - - private static string EscapeNewlines(string text) - { - return text.Replace("\n", "\\n").Replace("\r\n", "\\r\\n"); - } - } -} diff --git a/src/Components/Components/src/RenderTree/RenderTreeFrameType.cs b/src/Components/Components/src/RenderTree/RenderTreeFrameType.cs deleted file mode 100644 index e73119e038..0000000000 --- a/src/Components/Components/src/RenderTree/RenderTreeFrameType.cs +++ /dev/null @@ -1,66 +0,0 @@ -// 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. - -#if IGNITOR -namespace Ignitor -#else -namespace Microsoft.AspNetCore.Components.RenderTree -#endif -{ - /// - /// Types in the Microsoft.AspNetCore.Components.RenderTree are not recommended for use outside - /// of the Blazor framework. These types will change in future release. - /// - // - // Describes the type of a . - public enum RenderTreeFrameType: short - { - /// - /// Used only for unintialized frames. - /// - None = 0, - - /// - /// Represents a container for other frames. - /// - Element = 1, - - /// - /// Represents text content. - /// - Text = 2, - - /// - /// Represents a key-value pair associated with another . - /// - Attribute = 3, - - /// - /// Represents a child component. - /// - Component = 4, - - /// - /// Defines the boundary around range of sibling frames that should be treated as an - /// unsplittable group for the purposes of diffing. This is typically used when appending - /// a tree fragment generated by external code, because the sequence numbers in that tree - /// fragment are not comparable to sequence numbers outside it. - /// - Region = 5, - - /// - /// Represents an instruction to capture or update a reference to the parent element. - /// - ElementReferenceCapture = 6, - - /// - /// Represents an instruction to capture or update a reference to the parent component. - /// - ComponentReferenceCapture = 7, - - /// - /// Represents a block of markup content. - /// - Markup = 8, - } -} diff --git a/src/Components/Components/src/RenderTree/Renderer.Log.cs b/src/Components/Components/src/RenderTree/Renderer.Log.cs deleted file mode 100644 index 9362ecf4f5..0000000000 --- a/src/Components/Components/src/RenderTree/Renderer.Log.cs +++ /dev/null @@ -1,66 +0,0 @@ -// 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 Microsoft.AspNetCore.Components.Rendering; -using Microsoft.Extensions.Logging; - -namespace Microsoft.AspNetCore.Components.RenderTree -{ - public abstract partial class Renderer - { - internal static class Log - { - private static readonly Action _initializingChildComponent = - LoggerMessage.Define(LogLevel.Debug, new EventId(1, "InitializingChildComponent"), "Initializing component {ComponentId} ({ComponentType}) as child of {ParentComponentId} ({ParentComponentId})"); - - private static readonly Action _initializingRootComponent = - LoggerMessage.Define(LogLevel.Debug, new EventId(2, "InitializingRootComponent"), "Initializing root component {ComponentId} ({ComponentType})"); - - private static readonly Action _renderingComponent = - LoggerMessage.Define(LogLevel.Debug, new EventId(3, "RenderingComponent"), "Rendering component {ComponentId} of type {ComponentType}"); - - private static readonly Action _disposingComponent = - LoggerMessage.Define(LogLevel.Debug, new EventId(4, "DisposingComponent"), "Disposing component {ComponentId} of type {ComponentType}"); - - private static readonly Action _handlingEvent = - LoggerMessage.Define(LogLevel.Debug, new EventId(5, "HandlingEvent"), "Handling event {EventId} of type '{EventType}'"); - - public static void InitializingComponent(ILogger logger, ComponentState componentState, ComponentState parentComponentState) - { - if (logger.IsEnabled(LogLevel.Debug)) // This is almost always false, so skip the evaluations - { - if (parentComponentState == null) - { - _initializingRootComponent(logger, componentState.ComponentId, componentState.Component.GetType(), null); - } - else - { - _initializingChildComponent(logger, componentState.ComponentId, componentState.Component.GetType(), parentComponentState.ComponentId, parentComponentState.Component.GetType(), null); - } - } - } - - public static void RenderingComponent(ILogger logger, ComponentState componentState) - { - if (logger.IsEnabled(LogLevel.Debug)) // This is almost always false, so skip the evaluations - { - _renderingComponent(logger, componentState.ComponentId, componentState.Component.GetType(), null); - } - } - - public static void DisposingComponent(ILogger logger, ComponentState componentState) - { - if (logger.IsEnabled(LogLevel.Debug)) // This is almost always false, so skip the evaluations - { - _disposingComponent(logger, componentState.ComponentId, componentState.Component.GetType(), null); - } - } - - public static void HandlingEvent(ILogger logger, ulong eventHandlerId, EventArgs eventArgs) - { - _handlingEvent(logger, eventHandlerId, eventArgs?.GetType().Name ?? "null", null); - } - } - } -} diff --git a/src/Components/Components/src/RenderTree/Renderer.cs b/src/Components/Components/src/RenderTree/Renderer.cs deleted file mode 100644 index 05cfb41abe..0000000000 --- a/src/Components/Components/src/RenderTree/Renderer.cs +++ /dev/null @@ -1,737 +0,0 @@ -// 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.Collections.Generic; -using System.Diagnostics; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Components.Rendering; -using Microsoft.Extensions.Logging; - -namespace Microsoft.AspNetCore.Components.RenderTree -{ - /// - /// Types in the Microsoft.AspNetCore.Components.RenderTree are not recommended for use outside - /// of the Blazor framework. These types will change in a future release. - /// - // - // Provides mechanisms for rendering hierarchies of instances, - // dispatching events to them, and notifying when the user interface is being updated. - public abstract partial class Renderer : IDisposable - { - private readonly IServiceProvider _serviceProvider; - private readonly Dictionary _componentStateById = new Dictionary(); - private readonly RenderBatchBuilder _batchBuilder = new RenderBatchBuilder(); - private readonly Dictionary _eventBindings = new Dictionary(); - private readonly Dictionary _eventHandlerIdReplacements = new Dictionary(); - private readonly ILogger _logger; - - private int _nextComponentId = 0; // TODO: change to 'long' when Mono .NET->JS interop supports it - private bool _isBatchInProgress; - private ulong _lastEventHandlerId; - private List _pendingTasks; - private bool _disposed; - - /// - /// Allows the caller to handle exceptions from the SynchronizationContext when one is available. - /// - public event UnhandledExceptionEventHandler UnhandledSynchronizationException - { - add - { - Dispatcher.UnhandledException += value; - } - remove - { - Dispatcher.UnhandledException -= value; - } - } - - /// - /// Constructs an instance of . - /// - /// The to be used when initializing components. - /// The . - public Renderer(IServiceProvider serviceProvider, ILoggerFactory loggerFactory) - { - if (serviceProvider is null) - { - throw new ArgumentNullException(nameof(serviceProvider)); - } - - if (loggerFactory is null) - { - throw new ArgumentNullException(nameof(loggerFactory)); - } - - _serviceProvider = serviceProvider; - _logger = loggerFactory.CreateLogger(); - } - - /// - /// Gets the associated with this . - /// - public abstract Dispatcher Dispatcher { get; } - - /// - /// Constructs a new component of the specified type. - /// - /// The type of the component to instantiate. - /// The component instance. - protected IComponent InstantiateComponent(Type componentType) - => ComponentFactory.Instance.InstantiateComponent(_serviceProvider, componentType); - - /// - /// Associates the with the , assigning - /// an identifier that is unique within the scope of the . - /// - /// The component. - /// The component's assigned identifier. - // Internal for unit testing - protected internal int AssignRootComponentId(IComponent component) - => AttachAndInitComponent(component, -1).ComponentId; - - /// - /// Gets the current render tree for a given component. - /// - /// The id for the component. - /// The representing the current render tree. - protected ArrayRange GetCurrentRenderTreeFrames(int componentId) => GetRequiredComponentState(componentId).CurrentRenderTree.GetFrames(); - - /// - /// Performs the first render for a root component, waiting for this component and all - /// children components to finish rendering in case there is any asynchronous work being - /// done by any of the components. After this, the root component - /// makes its own decisions about when to re-render, so there is no need to call - /// this more than once. - /// - /// The ID returned by . - /// - /// Rendering a root component is an asynchronous operation. Clients may choose to not await the returned task to - /// start, but not wait for the entire render to complete. - /// - protected Task RenderRootComponentAsync(int componentId) - { - return RenderRootComponentAsync(componentId, ParameterView.Empty); - } - - /// - /// Performs the first render for a root component, waiting for this component and all - /// children components to finish rendering in case there is any asynchronous work being - /// done by any of the components. After this, the root component - /// makes its own decisions about when to re-render, so there is no need to call - /// this more than once. - /// - /// The ID returned by . - /// The with the initial parameters to use for rendering. - /// - /// Rendering a root component is an asynchronous operation. Clients may choose to not await the returned task to - /// start, but not wait for the entire render to complete. - /// - protected async Task RenderRootComponentAsync(int componentId, ParameterView initialParameters) - { - if (Interlocked.CompareExchange(ref _pendingTasks, new List(), null) != null) - { - throw new InvalidOperationException("There is an ongoing rendering in progress."); - } - - // During the rendering process we keep a list of components performing work in _pendingTasks. - // _renderer.AddToPendingTasks will be called by ComponentState.SetDirectParameters to add the - // the Task produced by Component.SetParametersAsync to _pendingTasks in order to track the - // remaining work. - // During the synchronous rendering process we don't wait for the pending asynchronous - // work to finish as it will simply trigger new renders that will be handled afterwards. - // During the asynchronous rendering process we want to wait up untill al components have - // finished rendering so that we can produce the complete output. - var componentState = GetRequiredComponentState(componentId); - componentState.SetDirectParameters(initialParameters); - - try - { - await ProcessAsynchronousWork(); - Debug.Assert(_pendingTasks.Count == 0); - } - finally - { - _pendingTasks = null; - } - } - - /// - /// Allows derived types to handle exceptions during rendering. Defaults to rethrowing the original exception. - /// - /// The . - protected abstract void HandleException(Exception exception); - - private async Task ProcessAsynchronousWork() - { - // Child components SetParametersAsync are stored in the queue of pending tasks, - // which might trigger further renders. - while (_pendingTasks.Count > 0) - { - // Create a Task that represents the remaining ongoing work for the rendering process - var pendingWork = Task.WhenAll(_pendingTasks); - - // Clear all pending work. - _pendingTasks.Clear(); - - // new work might be added before we check again as a result of waiting for all - // the child components to finish executing SetParametersAsync - await pendingWork; - } - } - - private ComponentState AttachAndInitComponent(IComponent component, int parentComponentId) - { - var componentId = _nextComponentId++; - var parentComponentState = GetOptionalComponentState(parentComponentId); - var componentState = new ComponentState(this, componentId, component, parentComponentState); - Log.InitializingComponent(_logger, componentState, parentComponentState); - _componentStateById.Add(componentId, componentState); - component.Attach(new RenderHandle(this, componentId)); - return componentState; - } - - /// - /// Updates the visible UI. - /// - /// The changes to the UI since the previous call. - /// A to represent the UI update process. - protected abstract Task UpdateDisplayAsync(in RenderBatch renderBatch); - - /// - /// Notifies the renderer that an event has occurred. - /// - /// The value from the original event attribute. - /// Arguments to be passed to the event handler. - /// Information that the renderer can use to update the state of the existing render tree to match the UI. - /// - /// A which will complete once all asynchronous processing related to the event - /// has completed. - /// - public virtual Task DispatchEventAsync(ulong eventHandlerId, EventFieldInfo fieldInfo, EventArgs eventArgs) - { - Dispatcher.AssertAccess(); - - if (!_eventBindings.TryGetValue(eventHandlerId, out var callback)) - { - throw new ArgumentException($"There is no event handler associated with this event. EventId: '{eventHandlerId}'.", nameof(eventHandlerId)); - } - - Log.HandlingEvent(_logger, eventHandlerId, eventArgs); - - if (fieldInfo != null) - { - var latestEquivalentEventHandlerId = FindLatestEventHandlerIdInChain(eventHandlerId); - UpdateRenderTreeToMatchClientState(latestEquivalentEventHandlerId, fieldInfo); - } - - Task task = null; - try - { - // The event handler might request multiple renders in sequence. Capture them - // all in a single batch. - _isBatchInProgress = true; - - task = callback.InvokeAsync(eventArgs); - } - catch (Exception e) - { - HandleException(e); - return Task.CompletedTask; - } - finally - { - _isBatchInProgress = false; - - // Since the task has yielded - process any queued rendering work before we return control - // to the caller. - ProcessPendingRender(); - } - - // Task completed synchronously or is still running. We already processed all of the rendering - // work that was queued so let our error handler deal with it. - return GetErrorHandledTask(task); - } - - internal void InstantiateChildComponentOnFrame(ref RenderTreeFrame frame, int parentComponentId) - { - if (frame.FrameType != RenderTreeFrameType.Component) - { - throw new ArgumentException($"The frame's {nameof(RenderTreeFrame.FrameType)} property must equal {RenderTreeFrameType.Component}", nameof(frame)); - } - - if (frame.ComponentState != null) - { - throw new ArgumentException($"The frame already has a non-null component instance", nameof(frame)); - } - - var newComponent = InstantiateComponent(frame.ComponentType); - var newComponentState = AttachAndInitComponent(newComponent, parentComponentId); - frame = frame.WithComponent(newComponentState); - } - - internal void AddToPendingTasks(Task task) - { - switch (task == null ? TaskStatus.RanToCompletion : task.Status) - { - // If it's already completed synchronously, no need to add it to the list of - // pending Tasks as no further render (we already rerender synchronously) will. - // happen. - case TaskStatus.RanToCompletion: - case TaskStatus.Canceled: - break; - case TaskStatus.Faulted: - // We want to immediately handle exceptions if the task failed synchronously instead of - // waiting for it to throw later. This can happen if the task is produced by - // an 'async' state machine (the ones generated using async/await) where even - // the synchronous exceptions will get captured and converted into a faulted - // task. - HandleException(task.Exception.GetBaseException()); - break; - default: - // It's important to evaluate the following even if we're not going to use - // handledErrorTask below, because it has the side-effect of calling HandleException. - var handledErrorTask = GetErrorHandledTask(task); - - // The pendingTasks collection is only used during prerendering to track quiescence, - // so will be null at other times. - _pendingTasks?.Add(handledErrorTask); - - break; - } - } - - internal void AssignEventHandlerId(ref RenderTreeFrame frame) - { - var id = ++_lastEventHandlerId; - - if (frame.AttributeValue is EventCallback callback) - { - // We hit this case when a EventCallback object is produced that needs an explicit receiver. - // Common cases for this are "chained bind" or "chained event handler" when a component - // accepts a delegate as a parameter and then hooks it up to a DOM event. - // - // When that happens we intentionally box the EventCallback because we need to hold on to - // the receiver. - _eventBindings.Add(id, callback); - } - else if (frame.AttributeValue is MulticastDelegate @delegate) - { - // This is the common case for a delegate, where the receiver of the event - // is the same as delegate.Target. In this case since the receiver is implicit we can - // avoid boxing the EventCallback object and just re-hydrate it on the other side of the - // render tree. - _eventBindings.Add(id, new EventCallback(@delegate.Target as IHandleEvent, @delegate)); - } - - // NOTE: we do not to handle EventCallback here. EventCallback is only used when passing - // a callback to a component, and never when used to attaching a DOM event handler. - - frame = frame.WithAttributeEventHandlerId(id); - } - - /// - /// Schedules a render for the specified . Its display - /// will be populated using the specified . - /// - /// The ID of the component to render. - /// A that will supply the updated UI contents. - internal void AddToRenderQueue(int componentId, RenderFragment renderFragment) - { - Dispatcher.AssertAccess(); - - var componentState = GetOptionalComponentState(componentId); - if (componentState == null) - { - // If the component was already disposed, then its render handle trying to - // queue a render is a no-op. - return; - } - - _batchBuilder.ComponentRenderQueue.Enqueue( - new RenderQueueEntry(componentState, renderFragment)); - - if (!_isBatchInProgress) - { - ProcessPendingRender(); - } - } - - internal void TrackReplacedEventHandlerId(ulong oldEventHandlerId, ulong newEventHandlerId) - { - // Tracking the chain of old->new replacements allows us to interpret incoming EventFieldInfo - // values even if they refer to an event handler ID that's since been superseded. This is essential - // for tree patching to work in an async environment. - _eventHandlerIdReplacements.Add(oldEventHandlerId, newEventHandlerId); - } - - private ulong FindLatestEventHandlerIdInChain(ulong eventHandlerId) - { - while (_eventHandlerIdReplacements.TryGetValue(eventHandlerId, out var replacementEventHandlerId)) - { - eventHandlerId = replacementEventHandlerId; - } - - return eventHandlerId; - } - - private ComponentState GetRequiredComponentState(int componentId) - => _componentStateById.TryGetValue(componentId, out var componentState) - ? componentState - : throw new ArgumentException($"The renderer does not have a component with ID {componentId}."); - - private ComponentState GetOptionalComponentState(int componentId) - => _componentStateById.TryGetValue(componentId, out var componentState) - ? componentState - : null; - - /// - /// Processses pending renders requests from components if there are any. - /// - protected virtual void ProcessPendingRender() - { - if (_disposed) - { - throw new ObjectDisposedException(nameof(Renderer), "Cannot process pending renders after the renderer has been disposed."); - } - - ProcessRenderQueue(); - } - - private void ProcessRenderQueue() - { - Dispatcher.AssertAccess(); - - if (_isBatchInProgress) - { - throw new InvalidOperationException("Cannot start a batch when one is already in progress."); - } - - _isBatchInProgress = true; - var updateDisplayTask = Task.CompletedTask; - - try - { - if (_batchBuilder.ComponentRenderQueue.Count == 0) - { - return; - } - - // Process render queue until empty - while (_batchBuilder.ComponentRenderQueue.Count > 0) - { - var nextToRender = _batchBuilder.ComponentRenderQueue.Dequeue(); - RenderInExistingBatch(nextToRender); - } - - var batch = _batchBuilder.ToBatch(); - updateDisplayTask = UpdateDisplayAsync(batch); - - // Fire off the execution of OnAfterRenderAsync, but don't wait for it - // if there is async work to be done. - _ = InvokeRenderCompletedCalls(batch.UpdatedComponents, updateDisplayTask); - } - catch (Exception e) - { - // Ensure we catch errors while running the render functions of the components. - HandleException(e); - return; - } - finally - { - RemoveEventHandlerIds(_batchBuilder.DisposedEventHandlerIds.ToRange(), updateDisplayTask); - _batchBuilder.ClearStateForCurrentBatch(); - _isBatchInProgress = false; - } - - // An OnAfterRenderAsync callback might have queued more work synchronously. - // Note: we do *not* re-render implicitly after the OnAfterRenderAsync-returned - // task (that would be an infinite loop). We only render after an explicit render - // request (e.g., StateHasChanged()). - if (_batchBuilder.ComponentRenderQueue.Count > 0) - { - ProcessRenderQueue(); - } - } - - private Task InvokeRenderCompletedCalls(ArrayRange updatedComponents, Task updateDisplayTask) - { - if (updateDisplayTask.IsCanceled) - { - // The display update was canceled. - // This can be due to a timeout on the components server-side case, or the renderer being disposed. - - // The latter case is normal during prerendering, as the render never fully completes (the display never - // gets updated, no references get populated and JavaScript interop is not available) and we simply discard - // the renderer after producing the prerendered content. - return Task.CompletedTask; - } - if (updateDisplayTask.IsFaulted) - { - // The display update failed so we don't care any more about running on render completed - // fallbacks as the entire rendering process is going to be torn down. - HandleException(updateDisplayTask.Exception); - return Task.CompletedTask; - } - - if (!updateDisplayTask.IsCompleted) - { - var updatedComponentsId = new int[updatedComponents.Count]; - var updatedComponentsArray = updatedComponents.Array; - for (int i = 0; i < updatedComponentsId.Length; i++) - { - updatedComponentsId[i] = updatedComponentsArray[i].ComponentId; - } - - return InvokeRenderCompletedCallsAfterUpdateDisplayTask(updateDisplayTask, updatedComponentsId); - } - - List batch = null; - var array = updatedComponents.Array; - for (var i = 0; i < updatedComponents.Count; i++) - { - var componentState = GetOptionalComponentState(array[i].ComponentId); - if (componentState != null) - { - NotifyRenderCompleted(componentState, ref batch); - } - } - - return batch != null ? - Task.WhenAll(batch) : - Task.CompletedTask; - - } - - private async Task InvokeRenderCompletedCallsAfterUpdateDisplayTask( - Task updateDisplayTask, - int[] updatedComponents) - { - try - { - await updateDisplayTask; - } - catch // avoiding exception filters for AOT runtimes - { - if (updateDisplayTask.IsCanceled) - { - return; - } - - HandleException(updateDisplayTask.Exception); - return; - } - - List batch = null; - var array = updatedComponents; - for (var i = 0; i < updatedComponents.Length; i++) - { - var componentState = GetOptionalComponentState(array[i]); - if (componentState != null) - { - NotifyRenderCompleted(componentState, ref batch); - } - } - - var result = batch != null ? - Task.WhenAll(batch) : - Task.CompletedTask; - - await result; - } - - private void NotifyRenderCompleted(ComponentState state, ref List batch) - { - // The component might be rendered and disposed in the same batch (if its parent - // was rendered later in the batch, and removed the child from the tree). - // This can also happen between batches if the UI takes some time to update and within - // that time the component gets removed out of the tree because the parent chose not to - // render it in a later batch. - // In any of the two cases mentioned happens, OnAfterRenderAsync won't run but that is - // ok. - var task = state.NotifyRenderCompletedAsync(); - - // We want to avoid allocations per rendering. Avoid allocating a state machine or an accumulator - // unless we absolutely have to. - if (task.IsCompleted) - { - if (task.Status == TaskStatus.RanToCompletion || task.Status == TaskStatus.Canceled) - { - // Nothing to do here. - return; - } - else if (task.Status == TaskStatus.Faulted) - { - HandleException(task.Exception); - return; - } - } - - // The Task is incomplete. - // Queue up the task and we can inspect it later. - batch = batch ?? new List(); - batch.Add(GetErrorHandledTask(task)); - } - - private void RenderInExistingBatch(RenderQueueEntry renderQueueEntry) - { - var componentState = renderQueueEntry.ComponentState; - Log.RenderingComponent(_logger, componentState); - componentState.RenderIntoBatch(_batchBuilder, renderQueueEntry.RenderFragment); - - List exceptions = null; - - // Process disposal queue now in case it causes further component renders to be enqueued - while (_batchBuilder.ComponentDisposalQueue.Count > 0) - { - var disposeComponentId = _batchBuilder.ComponentDisposalQueue.Dequeue(); - var disposeComponentState = GetRequiredComponentState(disposeComponentId); - Log.DisposingComponent(_logger, disposeComponentState); - if (!disposeComponentState.TryDisposeInBatch(_batchBuilder, out var exception)) - { - exceptions ??= new List(); - exceptions.Add(exception); - } - _componentStateById.Remove(disposeComponentId); - _batchBuilder.DisposedComponentIds.Append(disposeComponentId); - } - - if (exceptions?.Count > 1) - { - HandleException(new AggregateException("Exceptions were encountered while disposing components.", exceptions)); - } - else if (exceptions?.Count == 1) - { - HandleException(exceptions[0]); - } - } - - private void RemoveEventHandlerIds(ArrayRange eventHandlerIds, Task afterTaskIgnoreErrors) - { - if (eventHandlerIds.Count == 0) - { - return; - } - - if (afterTaskIgnoreErrors.IsCompleted) - { - var array = eventHandlerIds.Array; - var count = eventHandlerIds.Count; - for (var i = 0; i < count; i++) - { - var eventHandlerIdToRemove = array[i]; - _eventBindings.Remove(eventHandlerIdToRemove); - _eventHandlerIdReplacements.Remove(eventHandlerIdToRemove); - } - } - else - { - _ = ContinueAfterTask(eventHandlerIds, afterTaskIgnoreErrors); - } - - // Factor out the async part into a separate local method purely so, in the - // synchronous case, there's no state machine or task construction - async Task ContinueAfterTask(ArrayRange eventHandlerIds, Task afterTaskIgnoreErrors) - { - // We need to delay the actual removal (e.g., until we've confirmed the client - // has processed the batch and hence can be sure not to reuse the handler IDs - // any further). We must clone the data because the underlying RenderBatchBuilder - // may be reused and hence modified by an unrelated subsequent batch. - var eventHandlerIdsClone = eventHandlerIds.Clone(); - - try - { - await afterTaskIgnoreErrors; - } - catch (Exception) - { - // As per method contract, we're not error-handling the task. - // That remains the caller's business. - } - - // We know the next execution will complete synchronously, so no infinite loop - RemoveEventHandlerIds(eventHandlerIdsClone, Task.CompletedTask); - } - } - - private async Task GetErrorHandledTask(Task taskToHandle) - { - try - { - await taskToHandle; - } - catch (Exception ex) - { - if (!taskToHandle.IsCanceled) - { - // Ignore errors due to task cancellations. - HandleException(ex); - } - } - } - - private void UpdateRenderTreeToMatchClientState(ulong eventHandlerId, EventFieldInfo fieldInfo) - { - var componentState = GetOptionalComponentState(fieldInfo.ComponentId); - if (componentState != null) - { - RenderTreeUpdater.UpdateToMatchClientState( - componentState.CurrentRenderTree, - eventHandlerId, - fieldInfo.FieldValue); - } - } - - /// - /// Releases all resources currently used by this instance. - /// - /// if this method is being invoked by , otherwise . - protected virtual void Dispose(bool disposing) - { - _disposed = true; - - // It's important that we handle all exceptions here before reporting any of them. - // This way we can dispose all components before an error handler kicks in. - List exceptions = null; - foreach (var componentState in _componentStateById.Values) - { - Log.DisposingComponent(_logger, componentState); - - if (componentState.Component is IDisposable disposable) - { - try - { - componentState.Dispose(); - } - catch (Exception exception) - { - exceptions ??= new List(); - exceptions.Add(exception); - } - } - } - - _componentStateById.Clear(); // So we know they were all disposed - _batchBuilder.Dispose(); - - if (exceptions?.Count > 1) - { - HandleException(new AggregateException("Exceptions were encountered while disposing components.", exceptions)); - } - else if (exceptions?.Count == 1) - { - HandleException(exceptions[0]); - } - } - - /// - /// Releases all resources currently used by this instance. - /// - public void Dispose() - { - Dispose(disposing: true); - } - } -} diff --git a/src/Components/Components/src/RenderTree/StackObjectPool.cs b/src/Components/Components/src/RenderTree/StackObjectPool.cs deleted file mode 100644 index a2c9c1f524..0000000000 --- a/src/Components/Components/src/RenderTree/StackObjectPool.cs +++ /dev/null @@ -1,75 +0,0 @@ -// 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.AspNetCore.Components.RenderTree -{ - // This is a very simple object pool that requires Get and Return calls to be - // balanced as in a stack. It retains up to 'maxPreservedItems' instances in - // memory, then for any further requests it supplies untracked instances. - - internal class StackObjectPool where T : class - { - private readonly int _maxPreservedItems; - private readonly Func _instanceFactory; - private readonly T[] _contents; - private int _numSuppliedItems; - private int _numTrackedItems; - - public StackObjectPool(int maxPreservedItems, Func instanceFactory) - { - _maxPreservedItems = maxPreservedItems; - _instanceFactory = instanceFactory ?? throw new ArgumentNullException(nameof(instanceFactory)); - _contents = new T[_maxPreservedItems]; - } - - public T Get() - { - _numSuppliedItems++; - - if (_numSuppliedItems <= _maxPreservedItems) - { - if (_numTrackedItems < _numSuppliedItems) - { - // Need to allocate a new one - var newItem = _instanceFactory(); - _contents[_numTrackedItems++] = newItem; - return newItem; - } - else - { - // Can use one that's already in the pool - return _contents[_numSuppliedItems - 1]; - } - } - else - { - // Pool is full; return untracked instance - return _instanceFactory(); - } - } - - public void Return(T instance) - { - if (_numSuppliedItems <= 0) - { - throw new InvalidOperationException("There are no outstanding instances to return."); - } - else if (_numSuppliedItems <= _maxPreservedItems) - { - // We check you're returning the right instance only as a way of - // catching Get/Return mismatch bugs - var expectedInstance = _contents[_numSuppliedItems - 1]; - if (!ReferenceEquals(instance, expectedInstance)) - { - throw new ArgumentException($"Attempting to return wrong pooled instance. {nameof(Get)}/{nameof(Return)} calls must form a stack."); - } - } - - // It's a valid call. Track that we're no longer "supplying" the top item, - // but keep the instance in the _contents array for future reuse. - _numSuppliedItems--; - } - } -} diff --git a/src/Components/Components/src/Rendering/ComponentState.cs b/src/Components/Components/src/Rendering/ComponentState.cs deleted file mode 100644 index dc372424b9..0000000000 --- a/src/Components/Components/src/Rendering/ComponentState.cs +++ /dev/null @@ -1,218 +0,0 @@ -// 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.Collections.Generic; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Components.RenderTree; - -namespace Microsoft.AspNetCore.Components.Rendering -{ - /// - /// Tracks the rendering state associated with an instance - /// within the context of a . This is an internal implementation - /// detail of . - /// - internal class ComponentState : IDisposable - { - private readonly Renderer _renderer; - private readonly IReadOnlyList _cascadingParameters; - private readonly bool _hasAnyCascadingParameterSubscriptions; - private RenderTreeBuilder _renderTreeBuilderPrevious; - private ArrayBuilder _latestDirectParametersSnapshot; // Lazily instantiated - private bool _componentWasDisposed; - - /// - /// Constructs an instance of . - /// - /// The with which the new instance should be associated. - /// The externally visible identifier for the . The identifier must be unique in the context of the . - /// The whose state is being tracked. - /// The for the parent component, or null if this is a root component. - public ComponentState(Renderer renderer, int componentId, IComponent component, ComponentState parentComponentState) - { - ComponentId = componentId; - ParentComponentState = parentComponentState; - Component = component ?? throw new ArgumentNullException(nameof(component)); - _renderer = renderer ?? throw new ArgumentNullException(nameof(renderer)); - _cascadingParameters = CascadingParameterState.FindCascadingParameters(this); - CurrentRenderTree = new RenderTreeBuilder(); - _renderTreeBuilderPrevious = new RenderTreeBuilder(); - - if (_cascadingParameters != null) - { - _hasAnyCascadingParameterSubscriptions = AddCascadingParameterSubscriptions(); - } - } - - // TODO: Change the type to 'long' when the Mono runtime has more complete support for passing longs in .NET->JS calls - public int ComponentId { get; } - public IComponent Component { get; } - public ComponentState ParentComponentState { get; } - public RenderTreeBuilder CurrentRenderTree { get; private set; } - - public void RenderIntoBatch(RenderBatchBuilder batchBuilder, RenderFragment renderFragment) - { - // A component might be in the render queue already before getting disposed by an - // earlier entry in the render queue. In that case, rendering is a no-op. - if (_componentWasDisposed) - { - return; - } - - // Swap the old and new tree builders - (CurrentRenderTree, _renderTreeBuilderPrevious) = (_renderTreeBuilderPrevious, CurrentRenderTree); - - CurrentRenderTree.Clear(); - renderFragment(CurrentRenderTree); - - var diff = RenderTreeDiffBuilder.ComputeDiff( - _renderer, - batchBuilder, - ComponentId, - _renderTreeBuilderPrevious.GetFrames(), - CurrentRenderTree.GetFrames()); - batchBuilder.UpdatedComponentDiffs.Append(diff); - batchBuilder.InvalidateParameterViews(); - } - - public bool TryDisposeInBatch(RenderBatchBuilder batchBuilder, out Exception exception) - { - _componentWasDisposed = true; - exception = null; - - try - { - if (Component is IDisposable disposable) - { - disposable.Dispose(); - } - } - catch (Exception ex) - { - exception = ex; - } - - // We don't expect these things to throw. - RenderTreeDiffBuilder.DisposeFrames(batchBuilder, CurrentRenderTree.GetFrames()); - - if (_hasAnyCascadingParameterSubscriptions) - { - RemoveCascadingParameterSubscriptions(); - } - - DisposeBuffers(); - - return exception == null; - } - - // Callers expect this method to always return a faulted task. - public Task NotifyRenderCompletedAsync() - { - if (Component is IHandleAfterRender handlerAfterRender) - { - try - { - return handlerAfterRender.OnAfterRenderAsync(); - } - catch (OperationCanceledException cex) - { - return Task.FromCanceled(cex.CancellationToken); - } - catch (Exception ex) - { - return Task.FromException(ex); - } - } - - return Task.CompletedTask; - } - - public void SetDirectParameters(ParameterView parameters) - { - // Note: We should be careful to ensure that the framework never calls - // IComponent.SetParametersAsync directly elsewhere. We should only call it - // via ComponentState.SetDirectParameters (or NotifyCascadingValueChanged below). - // If we bypass this, the component won't receive the cascading parameters nor - // will it update its snapshot of direct parameters. - - if (_hasAnyCascadingParameterSubscriptions) - { - // We may need to replay these direct parameters later (in NotifyCascadingValueChanged), - // but we can't guarantee that the original underlying data won't have mutated in the - // meantime, since it's just an index into the parent's RenderTreeFrames buffer. - if (_latestDirectParametersSnapshot == null) - { - _latestDirectParametersSnapshot = new ArrayBuilder(); - } - - parameters.CaptureSnapshot(_latestDirectParametersSnapshot); - } - - if (_cascadingParameters != null) - { - parameters = parameters.WithCascadingParameters(_cascadingParameters); - } - - _renderer.AddToPendingTasks(Component.SetParametersAsync(parameters)); - } - - public void NotifyCascadingValueChanged(in ParameterViewLifetime lifetime) - { - var directParams = _latestDirectParametersSnapshot != null - ? new ParameterView(lifetime, _latestDirectParametersSnapshot.Buffer, 0) - : ParameterView.Empty; - var allParams = directParams.WithCascadingParameters(_cascadingParameters); - var task = Component.SetParametersAsync(allParams); - _renderer.AddToPendingTasks(task); - } - - private bool AddCascadingParameterSubscriptions() - { - var hasSubscription = false; - var numCascadingParameters = _cascadingParameters.Count; - - for (var i = 0; i < numCascadingParameters; i++) - { - var valueSupplier = _cascadingParameters[i].ValueSupplier; - if (!valueSupplier.CurrentValueIsFixed) - { - valueSupplier.Subscribe(this); - hasSubscription = true; - } - } - - return hasSubscription; - } - - private void RemoveCascadingParameterSubscriptions() - { - var numCascadingParameters = _cascadingParameters.Count; - for (var i = 0; i < numCascadingParameters; i++) - { - var supplier = _cascadingParameters[i].ValueSupplier; - if (!supplier.CurrentValueIsFixed) - { - supplier.Unsubscribe(this); - } - } - } - - public void Dispose() - { - DisposeBuffers(); - - if (Component is IDisposable disposable) - { - disposable.Dispose(); - } - } - - private void DisposeBuffers() - { - ((IDisposable)_renderTreeBuilderPrevious).Dispose(); - ((IDisposable)CurrentRenderTree).Dispose(); - _latestDirectParametersSnapshot?.Dispose(); - } - } -} diff --git a/src/Components/Components/src/Rendering/KeyedItemInfo.cs b/src/Components/Components/src/Rendering/KeyedItemInfo.cs deleted file mode 100644 index c8a7de5e1a..0000000000 --- a/src/Components/Components/src/Rendering/KeyedItemInfo.cs +++ /dev/null @@ -1,35 +0,0 @@ -// 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. - -namespace Microsoft.AspNetCore.Components.Rendering -{ - // Used internally during diffing to track what we know about keyed items and their positions - internal readonly struct KeyedItemInfo - { - public readonly int OldIndex; - public readonly int NewIndex; - public readonly int OldSiblingIndex; - public readonly int NewSiblingIndex; - - public KeyedItemInfo(int oldIndex, int newIndex) - { - OldIndex = oldIndex; - NewIndex = newIndex; - OldSiblingIndex = -1; - NewSiblingIndex = -1; - } - - private KeyedItemInfo(in KeyedItemInfo copyFrom, int oldSiblingIndex, int newSiblingIndex) - { - this = copyFrom; - OldSiblingIndex = oldSiblingIndex; - NewSiblingIndex = newSiblingIndex; - } - - public KeyedItemInfo WithOldSiblingIndex(int oldSiblingIndex) - => new KeyedItemInfo(this, oldSiblingIndex, NewSiblingIndex); - - public KeyedItemInfo WithNewSiblingIndex(int newSiblingIndex) - => new KeyedItemInfo(this, OldSiblingIndex, newSiblingIndex); - } -} diff --git a/src/Components/Components/src/Rendering/ParameterViewLifetime.cs b/src/Components/Components/src/Rendering/ParameterViewLifetime.cs deleted file mode 100644 index aefcb89180..0000000000 --- a/src/Components/Components/src/Rendering/ParameterViewLifetime.cs +++ /dev/null @@ -1,31 +0,0 @@ -// 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.AspNetCore.Components.Rendering -{ - internal readonly struct ParameterViewLifetime - { - private readonly RenderBatchBuilder _owner; - private readonly int _stamp; - - public static readonly ParameterViewLifetime Unbound = default; - - public ParameterViewLifetime(RenderBatchBuilder owner) - { - _owner = owner; - _stamp = owner.ParameterViewValidityStamp; - } - - public void AssertNotExpired() - { - // If _owner is null, this instance is default(ParameterViewLifetime), which is - // the same as ParameterViewLifetime.Unbound. That means it never expires. - if (_owner != null && _owner.ParameterViewValidityStamp != _stamp) - { - throw new InvalidOperationException($"The {nameof(ParameterView)} instance can no longer be read because it has expired. {nameof(ParameterView)} can only be read synchronously and must not be stored for later use."); - } - } - } -} diff --git a/src/Components/Components/src/Rendering/RenderBatchBuilder.cs b/src/Components/Components/src/Rendering/RenderBatchBuilder.cs deleted file mode 100644 index d4223bbce2..0000000000 --- a/src/Components/Components/src/Rendering/RenderBatchBuilder.cs +++ /dev/null @@ -1,93 +0,0 @@ -// 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.Collections.Generic; -using Microsoft.AspNetCore.Components.RenderTree; - -namespace Microsoft.AspNetCore.Components.Rendering -{ - /// - /// Collects the data produced by the rendering system during the course - /// of rendering a single batch. This tracks both the final output data - /// and the intermediate states (such as the queue of components still to - /// be rendered). - /// - internal class RenderBatchBuilder : IDisposable - { - // A value that, if changed, causes expiry of all ParameterView instances issued - // for this RenderBatchBuilder. This is to prevent invalid reads from arrays that - // may have been returned to the shared pool. - private int _parameterViewValidityStamp; - - // Primary result data - public ArrayBuilder UpdatedComponentDiffs { get; } = new ArrayBuilder(); - public ArrayBuilder DisposedComponentIds { get; } = new ArrayBuilder(); - public ArrayBuilder DisposedEventHandlerIds { get; } = new ArrayBuilder(); - - // Buffers referenced by UpdatedComponentDiffs - public ArrayBuilder EditsBuffer { get; } = new ArrayBuilder(64); - public ArrayBuilder ReferenceFramesBuffer { get; } = new ArrayBuilder(64); - - // State of render pipeline - public Queue ComponentRenderQueue { get; } = new Queue(); - public Queue ComponentDisposalQueue { get; } = new Queue(); - - // Scratch data structure for understanding attribute diffs. - public Dictionary AttributeDiffSet { get; } = new Dictionary(); - - public int ParameterViewValidityStamp => _parameterViewValidityStamp; - - internal StackObjectPool> KeyedItemInfoDictionaryPool { get; } - = new StackObjectPool>(maxPreservedItems: 10, () => new Dictionary()); - - public void ClearStateForCurrentBatch() - { - // This method is used to reset the builder back to a default state so it can - // begin building the next batch. That means clearing all the tracked state, but - // *not* clearing ComponentRenderQueue because that may hold information about - // the next batch we want to build. We shouldn't ever need to clear - // ComponentRenderQueue explicitly, because it gets cleared as an aspect of - // processing the render queue. - - EditsBuffer.Clear(); - ReferenceFramesBuffer.Clear(); - UpdatedComponentDiffs.Clear(); - DisposedComponentIds.Clear(); - DisposedEventHandlerIds.Clear(); - AttributeDiffSet.Clear(); - } - - public RenderBatch ToBatch() - => new RenderBatch( - UpdatedComponentDiffs.ToRange(), - ReferenceFramesBuffer.ToRange(), - DisposedComponentIds.ToRange(), - DisposedEventHandlerIds.ToRange()); - - public void InvalidateParameterViews() - { - // Wrapping is fine because all that matters is whether a snapshotted value matches - // the current one. There's no plausible case where it wraps around and happens to - // increment all the way back to a previously-snapshotted value on the exact same - // call that's checking the value. - if (_parameterViewValidityStamp == int.MaxValue) - { - _parameterViewValidityStamp = int.MinValue; - } - else - { - _parameterViewValidityStamp++; - } - } - - public void Dispose() - { - EditsBuffer.Dispose(); - ReferenceFramesBuffer.Dispose(); - UpdatedComponentDiffs.Dispose(); - DisposedComponentIds.Dispose(); - DisposedEventHandlerIds.Dispose(); - } - } -} diff --git a/src/Components/Components/src/Rendering/RenderQueueEntry.cs b/src/Components/Components/src/Rendering/RenderQueueEntry.cs deleted file mode 100644 index 09e5e9c327..0000000000 --- a/src/Components/Components/src/Rendering/RenderQueueEntry.cs +++ /dev/null @@ -1,19 +0,0 @@ -// 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.AspNetCore.Components.Rendering -{ - internal readonly struct RenderQueueEntry - { - public readonly ComponentState ComponentState; - public readonly RenderFragment RenderFragment; - - public RenderQueueEntry(ComponentState componentState, RenderFragment renderFragment) - { - ComponentState = componentState; - RenderFragment = renderFragment ?? throw new ArgumentNullException(nameof(renderFragment)); - } - } -} diff --git a/src/Components/Components/src/Rendering/RenderTreeBuilder.cs b/src/Components/Components/src/Rendering/RenderTreeBuilder.cs deleted file mode 100644 index f8a28273e4..0000000000 --- a/src/Components/Components/src/Rendering/RenderTreeBuilder.cs +++ /dev/null @@ -1,773 +0,0 @@ -// 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.Collections.Generic; -using System.Diagnostics; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Components.RenderTree; - -namespace Microsoft.AspNetCore.Components.Rendering -{ - // IMPORTANT - // - // Many of these names are used in code generation. Keep these in sync with the code generation code - // See: aspnet/AspNetCore-Tooling - - /// - /// Provides methods for building a collection of entries. - /// - public sealed class RenderTreeBuilder : IDisposable - { - private readonly static object BoxedTrue = true; - private readonly static object BoxedFalse = false; - private readonly static string ComponentReferenceCaptureInvalidParentMessage = $"Component reference captures may only be added as children of frames of type {RenderTreeFrameType.Component}"; - - private readonly ArrayBuilder _entries = new ArrayBuilder(); - private readonly Stack _openElementIndices = new Stack(); - private RenderTreeFrameType? _lastNonAttributeFrameType; - private bool _hasSeenAddMultipleAttributes; - private Dictionary _seenAttributeNames; - - /// - /// The reserved parameter name used for supplying child content. - /// - private const string ChildContent = nameof(ChildContent); - - /// - /// Appends a frame representing an element, i.e., a container for other frames. - /// In order for the state to be valid, you must - /// also call immediately after appending the - /// new element's child frames. - /// - /// An integer that represents the position of the instruction in the source code. - /// A value representing the type of the element. - public void OpenElement(int sequence, string elementName) - { - // We are entering a new scope, since we track the "duplicate attributes" per - // element/component we might need to clean them up now. - if (_hasSeenAddMultipleAttributes) - { - var indexOfLastElementOrComponent = _openElementIndices.Peek(); - ProcessDuplicateAttributes(first: indexOfLastElementOrComponent + 1); - } - - _openElementIndices.Push(_entries.Count); - Append(RenderTreeFrame.Element(sequence, elementName)); - } - - /// - /// Marks a previously appended element frame as closed. Calls to this method - /// must be balanced with calls to . - /// - public void CloseElement() - { - var indexOfEntryBeingClosed = _openElementIndices.Pop(); - - // We might be closing an element with only attributes, run the duplicate cleanup pass - // if necessary. - if (_hasSeenAddMultipleAttributes) - { - ProcessDuplicateAttributes(first: indexOfEntryBeingClosed + 1); - } - - ref var entry = ref _entries.Buffer[indexOfEntryBeingClosed]; - entry = entry.WithElementSubtreeLength(_entries.Count - indexOfEntryBeingClosed); - } - - /// - /// Appends a frame representing markup content. - /// - /// An integer that represents the position of the instruction in the source code. - /// Content for the new markup frame. - public void AddMarkupContent(int sequence, string markupContent) - => Append(RenderTreeFrame.Markup(sequence, markupContent ?? string.Empty)); - - /// - /// Appends a frame representing text content. - /// - /// An integer that represents the position of the instruction in the source code. - /// Content for the new text frame. - public void AddContent(int sequence, string textContent) - => Append(RenderTreeFrame.Text(sequence, textContent ?? string.Empty)); - - /// - /// Appends frames representing an arbitrary fragment of content. - /// - /// An integer that represents the position of the instruction in the source code. - /// Content to append. - public void AddContent(int sequence, RenderFragment fragment) - { - if (fragment != null) - { - // We surround the fragment with a region delimiter to indicate that the - // sequence numbers inside the fragment are unrelated to the sequence numbers - // outside it. If we didn't do this, the diffing logic might produce inefficient - // diffs depending on how the sequence numbers compared. - OpenRegion(sequence); - fragment(this); - CloseRegion(); - } - } - - /// - /// Appends frames representing an arbitrary fragment of content. - /// - /// An integer that represents the position of the instruction in the source code. - /// Content to append. - /// The value used by . - public void AddContent(int sequence, RenderFragment fragment, TValue value) - { - if (fragment != null) - { - AddContent(sequence, fragment(value)); - } - } - - /// - /// Appends a frame representing markup content. - /// - /// An integer that represents the position of the instruction in the source code. - /// Content for the new markup frame. - public void AddContent(int sequence, MarkupString markupContent) - => AddMarkupContent(sequence, markupContent.Value); - - /// - /// Appends a frame representing text content. - /// - /// An integer that represents the position of the instruction in the source code. - /// Content for the new text frame. - public void AddContent(int sequence, object textContent) - => AddContent(sequence, textContent?.ToString()); - - /// - /// - /// Appends a frame representing a bool-valued attribute. - /// - /// - /// The attribute is associated with the most recently added element. If the value is false and the - /// current element is not a component, the frame will be omitted. - /// - /// - /// An integer that represents the position of the instruction in the source code. - /// The name of the attribute. - /// The value of the attribute. - public void AddAttribute(int sequence, string name, bool value) - { - AssertCanAddAttribute(); - if (_lastNonAttributeFrameType == RenderTreeFrameType.Component) - { - Append(RenderTreeFrame.Attribute(sequence, name, value ? BoxedTrue : BoxedFalse)); - } - else if (value) - { - // Don't add 'false' attributes for elements. We want booleans to map to the presence - // or absence of an attribute, and false => "False" which isn't falsy in js. - Append(RenderTreeFrame.Attribute(sequence, name, BoxedTrue)); - } - else - { - TrackAttributeName(name); - } - } - - /// - /// - /// Appends a frame representing a string-valued attribute. - /// - /// - /// The attribute is associated with the most recently added element. If the value is null and the - /// current element is not a component, the frame will be omitted. - /// - /// - /// An integer that represents the position of the instruction in the source code. - /// The name of the attribute. - /// The value of the attribute. - public void AddAttribute(int sequence, string name, string value) - { - AssertCanAddAttribute(); - if (value != null || _lastNonAttributeFrameType == RenderTreeFrameType.Component) - { - Append(RenderTreeFrame.Attribute(sequence, name, value)); - } - else - { - TrackAttributeName(name); - } - } - - /// - /// - /// Appends a frame representing a delegate-valued attribute. - /// - /// - /// The attribute is associated with the most recently added element. If the value is null and the - /// current element is not a component, the frame will be omitted. - /// - /// - /// An integer that represents the position of the instruction in the source code. - /// The name of the attribute. - /// The value of the attribute. - public void AddAttribute(int sequence, string name, MulticastDelegate value) - { - AssertCanAddAttribute(); - if (value != null || _lastNonAttributeFrameType == RenderTreeFrameType.Component) - { - Append(RenderTreeFrame.Attribute(sequence, name, value)); - } - else - { - TrackAttributeName(name); - } - } - - /// - /// - /// Appends a frame representing an attribute. - /// - /// - /// The attribute is associated with the most recently added element. If the value is null and the - /// current element is not a component, the frame will be omitted. - /// - /// - /// An integer that represents the position of the instruction in the source code. - /// The name of the attribute. - /// The value of the attribute. - /// - /// This method is provided for infrastructure purposes, and is used to support generated code - /// that uses . - /// - public void AddAttribute(int sequence, string name, EventCallback value) - { - AssertCanAddAttribute(); - if (_lastNonAttributeFrameType == RenderTreeFrameType.Component) - { - // Since this is a component, we need to preserve the type of the EventCallabck, so we have - // to box. - Append(RenderTreeFrame.Attribute(sequence, name, (object)value)); - } - else if (value.RequiresExplicitReceiver) - { - // If we need to preserve the receiver, we just box the EventCallback - // so we can get it out on the other side. - Append(RenderTreeFrame.Attribute(sequence, name, (object)value)); - } - else if (value.HasDelegate) - { - // In the common case the receiver is also the delegate's target, so we - // just need to retain the delegate. This allows us to avoid an allocation. - Append(RenderTreeFrame.Attribute(sequence, name, value.Delegate)); - } - else - { - // Track the attribute name if needed since we elided the frame. - TrackAttributeName(name); - } - } - - /// - /// - /// Appends a frame representing an attribute. - /// - /// - /// The attribute is associated with the most recently added element. If the value is null and the - /// current element is not a component, the frame will be omitted. - /// - /// - /// An integer that represents the position of the instruction in the source code. - /// The name of the attribute. - /// The value of the attribute. - /// - /// This method is provided for infrastructure purposes, and is used to support generated code - /// that uses . - /// - public void AddAttribute(int sequence, string name, EventCallback value) - { - AssertCanAddAttribute(); - if (_lastNonAttributeFrameType == RenderTreeFrameType.Component) - { - // Since this is a component, we need to preserve the type of the EventCallback, so we have - // to box. - Append(RenderTreeFrame.Attribute(sequence, name, (object)value)); - } - else if (value.RequiresExplicitReceiver) - { - // If we need to preserve the receiver - we convert this to an untyped EventCallback. We don't - // need to preserve the type of an EventCallback when it's invoked from the DOM. - Append(RenderTreeFrame.Attribute(sequence, name, (object)value.AsUntyped())); - } - else if (value.HasDelegate) - { - // In the common case the receiver is also the delegate's target, so we - // just need to retain the delegate. This allows us to avoid an allocation. - Append(RenderTreeFrame.Attribute(sequence, name, value.Delegate)); - } - else - { - // Track the attribute name if needed since we elided the frame. - TrackAttributeName(name); - } - } - - /// - /// Appends a frame representing a string-valued attribute. - /// The attribute is associated with the most recently added element. If the value is null, or - /// the value false and the current element is not a component, the - /// frame will be omitted. - /// - /// An integer that represents the position of the instruction in the source code. - /// The name of the attribute. - /// The value of the attribute. - public void AddAttribute(int sequence, string name, object value) - { - // This looks a bit daunting because we need to handle the boxed/object version of all of the - // types that AddAttribute special cases. - if (_lastNonAttributeFrameType == RenderTreeFrameType.Element) - { - if (value == null) - { - // Treat 'null' attribute values for elements as a conditional attribute. - TrackAttributeName(name); - } - else if (value is bool boolValue) - { - if (boolValue) - { - Append(RenderTreeFrame.Attribute(sequence, name, BoxedTrue)); - } - else - { - // Don't add anything for false bool value. - TrackAttributeName(name); - } - } - else if (value is IEventCallback callbackValue) - { - if (callbackValue.HasDelegate) - { - Append(RenderTreeFrame.Attribute(sequence, name, callbackValue.UnpackForRenderTree())); - } - else - { - TrackAttributeName(name); - } - } - else if (value is MulticastDelegate) - { - Append(RenderTreeFrame.Attribute(sequence, name, value)); - } - else - { - // The value is either a string, or should be treated as a string. - Append(RenderTreeFrame.Attribute(sequence, name, value.ToString())); - } - } - else if (_lastNonAttributeFrameType == RenderTreeFrameType.Component) - { - // If this is a component, we always want to preserve the original type. - Append(RenderTreeFrame.Attribute(sequence, name, value)); - } - else - { - // This is going to throw. Calling it just to get a consistent exception message. - AssertCanAddAttribute(); - } - } - - /// - /// - /// Appends a frame representing an attribute. - /// - /// - /// The attribute is associated with the most recently added element. - /// - /// - /// An integer that represents the position of the instruction in the source code. - /// A holding the name and value of the attribute. - public void AddAttribute(int sequence, in RenderTreeFrame frame) - { - if (frame.FrameType != RenderTreeFrameType.Attribute) - { - throw new ArgumentException($"The {nameof(frame.FrameType)} must be {RenderTreeFrameType.Attribute}."); - } - - AssertCanAddAttribute(); - Append(frame.WithAttributeSequence(sequence)); - } - - /// - /// Adds frames representing multiple attributes with the same sequence number. - /// - /// An integer that represents the position of the instruction in the source code. - /// A collection of key-value pairs representing attributes. - public void AddMultipleAttributes(int sequence, IEnumerable> attributes) - { - // Calling this up-front just to make sure we validate before mutating anything. - AssertCanAddAttribute(); - - if (attributes != null) - { - _hasSeenAddMultipleAttributes = true; - - foreach (var attribute in attributes) - { - // This will call the AddAttribute(int, string, object) overload. - // - // This is fine because we try to make the object overload behave identically - // to the others. - AddAttribute(sequence, attribute.Key, attribute.Value); - } - } - } - - /// - /// - /// Indicates that the preceding attribute represents an event handler - /// whose execution updates the attribute with name . - /// - /// - /// This information is used by the rendering system to determine whether - /// to accept a value update for the other attribute when receiving a - /// call to the event handler. - /// - /// - /// The name of another attribute whose value can be updated when the event handler is executed. - public void SetUpdatesAttributeName(string updatesAttributeName) - { - if (_entries.Count == 0) - { - throw new InvalidOperationException("No preceding attribute frame exists."); - } - - ref var prevFrame = ref _entries.Buffer[_entries.Count - 1]; - if (prevFrame.FrameType != RenderTreeFrameType.Attribute) - { - throw new InvalidOperationException($"Incorrect frame type: '{prevFrame.FrameType}'"); - } - - prevFrame = prevFrame.WithAttributeEventUpdatesAttributeName(updatesAttributeName); - } - - /// - /// Appends a frame representing a child component. - /// - /// The type of the child component. - /// An integer that represents the position of the instruction in the source code. - public void OpenComponent(int sequence) where TComponent : IComponent - => OpenComponentUnchecked(sequence, typeof(TComponent)); - - /// - /// Appends a frame representing a child component. - /// - /// An integer that represents the position of the instruction in the source code. - /// The type of the child component. - public void OpenComponent(int sequence, Type componentType) - { - if (!typeof(IComponent).IsAssignableFrom(componentType)) - { - throw new ArgumentException($"The component type must implement {typeof(IComponent).FullName}."); - } - - OpenComponentUnchecked(sequence, componentType); - } - - /// - /// Assigns the specified key value to the current element or component. - /// - /// The value for the key. - public void SetKey(object value) - { - if (value == null) - { - // Null is equivalent to not having set a key, which is valuable because Razor syntax doesn't have an - // easy way to have conditional directive attributes - return; - } - - var parentFrameIndex = GetCurrentParentFrameIndex(); - if (!parentFrameIndex.HasValue) - { - throw new InvalidOperationException("Cannot set a key outside the scope of a component or element."); - } - - var parentFrameIndexValue = parentFrameIndex.Value; - ref var parentFrame = ref _entries.Buffer[parentFrameIndexValue]; - switch (parentFrame.FrameType) - { - case RenderTreeFrameType.Element: - parentFrame = parentFrame.WithElementKey(value); // It's a ref var, so this writes to the array - break; - case RenderTreeFrameType.Component: - parentFrame = parentFrame.WithComponentKey(value); // It's a ref var, so this writes to the array - break; - default: - throw new InvalidOperationException($"Cannot set a key on a frame of type {parentFrame.FrameType}."); - } - } - - private void OpenComponentUnchecked(int sequence, Type componentType) - { - // We are entering a new scope, since we track the "duplicate attributes" per - // element/component we might need to clean them up now. - if (_hasSeenAddMultipleAttributes) - { - var indexOfLastElementOrComponent = _openElementIndices.Peek(); - ProcessDuplicateAttributes(first: indexOfLastElementOrComponent + 1); - } - - _openElementIndices.Push(_entries.Count); - Append(RenderTreeFrame.ChildComponent(sequence, componentType)); - } - - /// - /// Marks a previously appended component frame as closed. Calls to this method - /// must be balanced with calls to . - /// - public void CloseComponent() - { - var indexOfEntryBeingClosed = _openElementIndices.Pop(); - - // We might be closing a component with only attributes. Run the attribute cleanup pass - // if necessary. - if (_hasSeenAddMultipleAttributes) - { - ProcessDuplicateAttributes(first: indexOfEntryBeingClosed + 1); - } - - ref var entry = ref _entries.Buffer[indexOfEntryBeingClosed]; - entry = entry.WithComponentSubtreeLength(_entries.Count - indexOfEntryBeingClosed); - } - - /// - /// Appends a frame representing an instruction to capture a reference to the parent element. - /// - /// An integer that represents the position of the instruction in the source code. - /// An action to be invoked whenever the reference value changes. - public void AddElementReferenceCapture(int sequence, Action elementReferenceCaptureAction) - { - if (GetCurrentParentFrameType() != RenderTreeFrameType.Element) - { - throw new InvalidOperationException($"Element reference captures may only be added as children of frames of type {RenderTreeFrameType.Element}"); - } - - Append(RenderTreeFrame.ElementReferenceCapture(sequence, elementReferenceCaptureAction)); - } - - /// - /// Appends a frame representing an instruction to capture a reference to the parent component. - /// - /// An integer that represents the position of the instruction in the source code. - /// An action to be invoked whenever the reference value changes. - public void AddComponentReferenceCapture(int sequence, Action componentReferenceCaptureAction) - { - var parentFrameIndex = GetCurrentParentFrameIndex(); - if (!parentFrameIndex.HasValue) - { - throw new InvalidOperationException(ComponentReferenceCaptureInvalidParentMessage); - } - - var parentFrameIndexValue = parentFrameIndex.Value; - if (_entries.Buffer[parentFrameIndexValue].FrameType != RenderTreeFrameType.Component) - { - throw new InvalidOperationException(ComponentReferenceCaptureInvalidParentMessage); - } - - Append(RenderTreeFrame.ComponentReferenceCapture(sequence, componentReferenceCaptureAction, parentFrameIndexValue)); - } - - /// - /// Appends a frame representing a region of frames. - /// - /// An integer that represents the position of the instruction in the source code. - public void OpenRegion(int sequence) - { - // We are entering a new scope, since we track the "duplicate attributes" per - // element/component we might need to clean them up now. - if (_hasSeenAddMultipleAttributes) - { - var indexOfLastElementOrComponent = _openElementIndices.Peek(); - ProcessDuplicateAttributes(first: indexOfLastElementOrComponent + 1); - } - - _openElementIndices.Push(_entries.Count); - Append(RenderTreeFrame.Region(sequence)); - } - - /// - /// Marks a previously appended region frame as closed. Calls to this method - /// must be balanced with calls to . - /// - public void CloseRegion() - { - var indexOfEntryBeingClosed = _openElementIndices.Pop(); - ref var entry = ref _entries.Buffer[indexOfEntryBeingClosed]; - entry = entry.WithRegionSubtreeLength(_entries.Count - indexOfEntryBeingClosed); - } - - private void AssertCanAddAttribute() - { - if (_lastNonAttributeFrameType != RenderTreeFrameType.Element - && _lastNonAttributeFrameType != RenderTreeFrameType.Component) - { - throw new InvalidOperationException($"Attributes may only be added immediately after frames of type {RenderTreeFrameType.Element} or {RenderTreeFrameType.Component}"); - } - } - - private int? GetCurrentParentFrameIndex() - => _openElementIndices.Count == 0 ? (int?)null : _openElementIndices.Peek(); - - private RenderTreeFrameType? GetCurrentParentFrameType() - { - var parentIndex = GetCurrentParentFrameIndex(); - return parentIndex.HasValue - ? _entries.Buffer[parentIndex.Value].FrameType - : (RenderTreeFrameType?)null; - } - - /// - /// Clears the builder. - /// - public void Clear() - { - _entries.Clear(); - _openElementIndices.Clear(); - _lastNonAttributeFrameType = null; - _hasSeenAddMultipleAttributes = false; - _seenAttributeNames?.Clear(); - } - - // internal because this should only be used during the post-event tree patching logic - // It's expensive because it involves copying all the subsequent memory in the array - internal void InsertAttributeExpensive(int insertAtIndex, int sequence, string attributeName, object attributeValue) - { - // Replicate the same attribute omission logic as used elsewhere - if ((attributeValue == null) || (attributeValue is bool boolValue && !boolValue)) - { - return; - } - - _entries.InsertExpensive(insertAtIndex, RenderTreeFrame.Attribute(sequence, attributeName, attributeValue)); - } - - /// - /// Returns the values that have been appended. - /// - /// An array range of values. - public ArrayRange GetFrames() => - _entries.ToRange(); - - private void Append(in RenderTreeFrame frame) - { - var frameType = frame.FrameType; - _entries.Append(frame); - - if (frameType != RenderTreeFrameType.Attribute) - { - _lastNonAttributeFrameType = frame.FrameType; - } - } - - // Internal for testing - internal void ProcessDuplicateAttributes(int first) - { - Debug.Assert(_hasSeenAddMultipleAttributes); - - // When AddMultipleAttributes method has been called, we need to postprocess attributes while closing - // the element/component. However, we also don't know the end index we should look at because it - // will contain nested content. - var buffer = _entries.Buffer; - var last = _entries.Count - 1; - - for (var i = first; i <= last; i++) - { - if (buffer[i].FrameType != RenderTreeFrameType.Attribute) - { - last = i - 1; - break; - } - } - - // Now that we've found the last attribute, we can iterate backwards and process duplicates. - var seenAttributeNames = (_seenAttributeNames ??= new Dictionary(StringComparer.OrdinalIgnoreCase)); - for (var i = last; i >= first; i--) - { - ref var frame = ref buffer[i]; - Debug.Assert(frame.FrameType == RenderTreeFrameType.Attribute, $"Frame type is {frame.FrameType} at {i}"); - - if (!seenAttributeNames.TryGetValue(frame.AttributeName, out var index)) - { - // This is the first time seeing this attribute name. Add to the dictionary and move on. - seenAttributeNames.Add(frame.AttributeName, i); - } - else if (index < i) - { - // This attribute is overriding a "silent frame" where we didn't create a frame for an AddAttribute call. - // This is the case for a null event handler, or bool false value. - // - // We need to update our tracking, in case the attribute appeared 3 or more times. - seenAttributeNames[frame.AttributeName] = i; - } - else if (index > i) - { - // This attribute has been overridden. For now, blank out its name to *mark* it. We'll do a pass - // later to wipe it out. - frame = default; - } - else - { - // OK so index == i. How is that possible? Well it's possible for a "silent frame" immediately - // followed by setting the same attribute. Think of it this way, when we create a "silent frame" - // we have to track that attribute name with *some* index. - // - // The only index value we can safely use is _entries.Count (next available). This is fine because - // we never use these indexes to look stuff up, only for comparison. - // - // That gets you here, and there's no action to take. - } - } - - // This is the pass where we cleanup attributes that have been wiped out. - // - // We copy the entries we're keeping into the earlier parts of the list (preserving order). - // - // Note that we iterate to the end of the list here, there might be additional frames after the attributes - // (ref) or content) that need to move to the left. - var offset = first; - for (var i = first; i < _entries.Count; i++) - { - ref var frame = ref buffer[i]; - if (frame.FrameType != RenderTreeFrameType.None) - { - buffer[offset++] = frame; - } - } - - // Clean up now unused space at the end of the list. - var residue = _entries.Count - offset; - for (var i = 0; i < residue; i++) - { - _entries.RemoveLast(); - } - - seenAttributeNames.Clear(); - _hasSeenAddMultipleAttributes = false; - } - - // Internal for testing - internal void TrackAttributeName(string name) - { - if (!_hasSeenAddMultipleAttributes) - { - return; - } - - var seenAttributeNames = (_seenAttributeNames ??= new Dictionary(StringComparer.OrdinalIgnoreCase)); - seenAttributeNames[name] = _entries.Count; // See comment in ProcessAttributes for why this is OK. - } - - void IDisposable.Dispose() - { - _entries.Dispose(); - } - } -} diff --git a/src/Components/Components/src/Rendering/RenderTreeUpdater.cs b/src/Components/Components/src/Rendering/RenderTreeUpdater.cs deleted file mode 100644 index 139b3e09d7..0000000000 --- a/src/Components/Components/src/Rendering/RenderTreeUpdater.cs +++ /dev/null @@ -1,113 +0,0 @@ -// 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.AspNetCore.Components.RenderTree; - -namespace Microsoft.AspNetCore.Components.Rendering -{ - internal class RenderTreeUpdater - { - public static void UpdateToMatchClientState(RenderTreeBuilder renderTreeBuilder, ulong eventHandlerId, object newFieldValue) - { - // We only allow the client to supply string or bool currently, since those are the only kinds of - // values we output on attributes that go to the client - if (!(newFieldValue is string || newFieldValue is bool)) - { - return; - } - - // Find the element that contains the event handler - var frames = renderTreeBuilder.GetFrames(); - var framesArray = frames.Array; - var framesLength = frames.Count; - var closestElementFrameIndex = -1; - for (var frameIndex = 0; frameIndex < framesLength; frameIndex++) - { - ref var frame = ref framesArray[frameIndex]; - switch (frame.FrameType) - { - case RenderTreeFrameType.Element: - closestElementFrameIndex = frameIndex; - break; - case RenderTreeFrameType.Attribute: - if (frame.AttributeEventHandlerId == eventHandlerId) - { - if (!string.IsNullOrEmpty(frame.AttributeEventUpdatesAttributeName)) - { - UpdateFrameToMatchClientState( - renderTreeBuilder, - framesArray, - closestElementFrameIndex, - frame.AttributeEventUpdatesAttributeName, - newFieldValue); - } - - // Whether or not we did update the frame, that was the one that matches - // the event handler ID, so no need to look any further - return; - } - break; - } - } - } - - private static void UpdateFrameToMatchClientState(RenderTreeBuilder renderTreeBuilder, RenderTreeFrame[] framesArray, int elementFrameIndex, string attributeName, object attributeValue) - { - // Find the attribute frame - ref var elementFrame = ref framesArray[elementFrameIndex]; - var elementSubtreeEndIndexExcl = elementFrameIndex + elementFrame.ElementSubtreeLength; - for (var attributeFrameIndex = elementFrameIndex + 1; attributeFrameIndex < elementSubtreeEndIndexExcl; attributeFrameIndex++) - { - ref var attributeFrame = ref framesArray[attributeFrameIndex]; - if (attributeFrame.FrameType != RenderTreeFrameType.Attribute) - { - // We're now looking at the descendants not attributes, so the search is over - break; - } - - if (attributeFrame.AttributeName == attributeName) - { - // Found an existing attribute we can update - attributeFrame = attributeFrame.WithAttributeValue(attributeValue); - return; - } - } - - // If we get here, we didn't find the desired attribute, so we have to insert a new frame for it - var insertAtIndex = elementFrameIndex + 1; - renderTreeBuilder.InsertAttributeExpensive(insertAtIndex, RenderTreeDiffBuilder.SystemAddedAttributeSequenceNumber, attributeName, attributeValue); - framesArray = renderTreeBuilder.GetFrames().Array; // Refresh in case it mutated due to the expansion - - // Update subtree length for this and all ancestor containers - // Ancestors can only be regions or other elements, since components can't "contain" elements inline - // We only have to walk backwards, since later entries in the frames array can't contain an earlier one - for (var otherFrameIndex = elementFrameIndex; otherFrameIndex >= 0; otherFrameIndex--) - { - ref var otherFrame = ref framesArray[otherFrameIndex]; - switch (otherFrame.FrameType) - { - case RenderTreeFrameType.Element: - { - var otherFrameSubtreeLength = otherFrame.ElementSubtreeLength; - var otherFrameEndIndexExcl = otherFrameIndex + otherFrameSubtreeLength; - if (otherFrameEndIndexExcl > elementFrameIndex) // i.e., contains the element we're inserting into - { - otherFrame = otherFrame.WithElementSubtreeLength(otherFrameSubtreeLength + 1); - } - break; - } - case RenderTreeFrameType.Region: - { - var otherFrameSubtreeLength = otherFrame.RegionSubtreeLength; - var otherFrameEndIndexExcl = otherFrameIndex + otherFrameSubtreeLength; - if (otherFrameEndIndexExcl > elementFrameIndex) // i.e., contains the element we're inserting into - { - otherFrame = otherFrame.WithRegionSubtreeLength(otherFrameSubtreeLength + 1); - } - break; - } - } - } - } - } -} diff --git a/src/Components/Components/src/Rendering/RendererSynchronizationContext.cs b/src/Components/Components/src/Rendering/RendererSynchronizationContext.cs deleted file mode 100644 index 176e4d83e4..0000000000 --- a/src/Components/Components/src/Rendering/RendererSynchronizationContext.cs +++ /dev/null @@ -1,312 +0,0 @@ -// 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.Diagnostics; -using System.Threading; -using System.Threading.Tasks; - -namespace Microsoft.AspNetCore.Components.Rendering -{ - [DebuggerDisplay("{_state,nq}")] - internal class RendererSynchronizationContext : SynchronizationContext - { - private static readonly ContextCallback ExecutionContextThunk = (object state) => - { - var item = (WorkItem)state; - item.SynchronizationContext.ExecuteSynchronously(null, item.Callback, item.State); - }; - - private static readonly Action BackgroundWorkThunk = (Task task, object state) => - { - var item = (WorkItem)state; - item.SynchronizationContext.ExecuteBackground(item); - }; - - private readonly State _state; - - public event UnhandledExceptionEventHandler UnhandledException; - - public RendererSynchronizationContext() - : this(new State()) - { - } - - private RendererSynchronizationContext(State state) - { - _state = state; - } - - public Task InvokeAsync(Action action) - { - var completion = new RendererSynchronizationTaskCompletionSource(action); - ExecuteSynchronouslyIfPossible((state) => - { - var completion = (RendererSynchronizationTaskCompletionSource)state; - try - { - completion.Callback(); - completion.SetResult(null); - } - catch (OperationCanceledException) - { - completion.SetCanceled(); - } - catch (Exception exception) - { - completion.SetException(exception); - } - }, completion); - - return completion.Task; - } - - public Task InvokeAsync(Func asyncAction) - { - var completion = new RendererSynchronizationTaskCompletionSource, object>(asyncAction); - ExecuteSynchronouslyIfPossible(async (state) => - { - var completion = (RendererSynchronizationTaskCompletionSource, object>)state; - try - { - await completion.Callback(); - completion.SetResult(null); - } - catch (OperationCanceledException) - { - completion.SetCanceled(); - } - catch (Exception exception) - { - completion.SetException(exception); - } - }, completion); - - return completion.Task; - } - - public Task InvokeAsync(Func function) - { - var completion = new RendererSynchronizationTaskCompletionSource, TResult>(function); - ExecuteSynchronouslyIfPossible((state) => - { - var completion = (RendererSynchronizationTaskCompletionSource, TResult>)state; - try - { - var result = completion.Callback(); - completion.SetResult(result); - } - catch (OperationCanceledException) - { - completion.SetCanceled(); - } - catch (Exception exception) - { - completion.SetException(exception); - } - }, completion); - - return completion.Task; - } - - public Task InvokeAsync(Func> asyncFunction) - { - var completion = new RendererSynchronizationTaskCompletionSource>, TResult>(asyncFunction); - ExecuteSynchronouslyIfPossible(async (state) => - { - var completion = (RendererSynchronizationTaskCompletionSource>, TResult>)state; - try - { - var result = await completion.Callback(); - completion.SetResult(result); - } - catch (OperationCanceledException) - { - completion.SetCanceled(); - } - catch (Exception exception) - { - completion.SetException(exception); - } - }, completion); - - return completion.Task; - } - - // asynchronously runs the callback - // - // NOTE: this must always run async. It's not legal here to execute the work item synchronously. - public override void Post(SendOrPostCallback d, object state) - { - lock (_state.Lock) - { - _state.Task = Enqueue(_state.Task, d, state, forceAsync: true); - } - } - - // synchronously runs the callback - public override void Send(SendOrPostCallback d, object state) - { - Task antecedant; - var completion = new TaskCompletionSource(); - - lock (_state.Lock) - { - antecedant = _state.Task; - _state.Task = completion.Task; - } - - // We have to block. That's the contract of Send - we don't expect this to be used - // in many scenarios in Components. - // - // Using Wait here is ok because the antecedant task will never throw. - antecedant.Wait(); - - ExecuteSynchronously(completion, d, state); - } - - // shallow copy - public override SynchronizationContext CreateCopy() - { - return new RendererSynchronizationContext(_state); - } - - // Similar to Post, but it can runs the work item synchronously if the context is not busy. - // - // This is the main code path used by components, we want to be able to run async work but only dispatch - // if necessary. - private void ExecuteSynchronouslyIfPossible(SendOrPostCallback d, object state) - { - TaskCompletionSource completion; - lock (_state.Lock) - { - if (!_state.Task.IsCompleted) - { - _state.Task = Enqueue(_state.Task, d, state); - return; - } - - // We can execute this synchronously because nothing is currently running - // or queued. - completion = new TaskCompletionSource(); - _state.Task = completion.Task; - } - - ExecuteSynchronously(completion, d, state); - } - - private Task Enqueue(Task antecedant, SendOrPostCallback d, object state, bool forceAsync = false) - { - // If we get here is means that a callback is being explicitly queued. Let's instead add it to the queue and yield. - // - // We use our own queue here to maintain the execution order of the callbacks scheduled here. Also - // we need a queue rather than just scheduling an item in the thread pool - those items would immediately - // block and hurt scalability. - // - // We need to capture the execution context so we can restore it later. This code is similar to - // the call path of ThreadPool.QueueUserWorkItem and System.Threading.QueueUserWorkItemCallback. - ExecutionContext executionContext = null; - if (!ExecutionContext.IsFlowSuppressed()) - { - executionContext = ExecutionContext.Capture(); - } - - var flags = forceAsync ? TaskContinuationOptions.RunContinuationsAsynchronously : TaskContinuationOptions.None; - return antecedant.ContinueWith(BackgroundWorkThunk, new WorkItem() - { - SynchronizationContext = this, - ExecutionContext = executionContext, - Callback = d, - State = state, - }, CancellationToken.None, flags, TaskScheduler.Current); - } - - private void ExecuteSynchronously( - TaskCompletionSource completion, - SendOrPostCallback d, - object state) - { - var original = Current; - try - { - SetSynchronizationContext(this); - _state.IsBusy = true; - - d(state); - } - finally - { - _state.IsBusy = false; - SetSynchronizationContext(original); - - completion?.SetResult(null); - } - } - - private void ExecuteBackground(WorkItem item) - { - if (item.ExecutionContext == null) - { - try - { - ExecuteSynchronously(null, item.Callback, item.State); - } - catch (Exception ex) - { - DispatchException(ex); - } - - return; - } - - // Perf - using a static thunk here to avoid a delegate allocation. - try - { - ExecutionContext.Run(item.ExecutionContext, ExecutionContextThunk, item); - } - catch (Exception ex) - { - DispatchException(ex); - } - } - - private void DispatchException(Exception ex) - { - var handler = UnhandledException; - if (handler != null) - { - handler(this, new UnhandledExceptionEventArgs(ex, isTerminating: false)); - } - } - - private class State - { - public bool IsBusy; // Just for debugging - public object Lock = new object(); - public Task Task = Task.CompletedTask; - - public override string ToString() - { - return $"{{ Busy: {IsBusy}, Pending Task: {Task} }}"; - } - } - - private class WorkItem - { - public RendererSynchronizationContext SynchronizationContext; - public ExecutionContext ExecutionContext; - public SendOrPostCallback Callback; - public object State; - } - - private class RendererSynchronizationTaskCompletionSource : TaskCompletionSource - { - public RendererSynchronizationTaskCompletionSource(TCallback callback) - { - Callback = callback; - } - - public TCallback Callback { get; } - } - } -} diff --git a/src/Components/Components/src/Rendering/RendererSynchronizationContextDispatcher.cs b/src/Components/Components/src/Rendering/RendererSynchronizationContextDispatcher.cs deleted file mode 100644 index e09488431c..0000000000 --- a/src/Components/Components/src/Rendering/RendererSynchronizationContextDispatcher.cs +++ /dev/null @@ -1,66 +0,0 @@ -// 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 workItem) - { - if (CheckAccess()) - { - return workItem(); - } - - return _context.InvokeAsync(workItem); - } - - public override Task InvokeAsync(Func workItem) - { - if (CheckAccess()) - { - return Task.FromResult(workItem()); - } - - return _context.InvokeAsync(workItem); - } - - public override Task InvokeAsync(Func> workItem) - { - if (CheckAccess()) - { - return workItem(); - } - - return _context.InvokeAsync(workItem); - } - } -} diff --git a/src/Components/Components/src/RouteAttribute.cs b/src/Components/Components/src/RouteAttribute.cs deleted file mode 100644 index 6e3214845b..0000000000 --- a/src/Components/Components/src/RouteAttribute.cs +++ /dev/null @@ -1,33 +0,0 @@ -// 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.AspNetCore.Components -{ - /// - /// Indicates that the associated component should match the specified route template pattern. - /// - [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false)] - public sealed class RouteAttribute : Attribute - { - /// - /// Constructs an instance of . - /// - /// The route template. - public RouteAttribute(string template) - { - if (template == null) - { - throw new ArgumentNullException(nameof(template)); - } - - Template = template; - } - - /// - /// Gets the route template. - /// - public string Template { get; } - } -} diff --git a/src/Components/Components/src/RouteView.cs b/src/Components/Components/src/RouteView.cs deleted file mode 100644 index 6f77169e06..0000000000 --- a/src/Components/Components/src/RouteView.cs +++ /dev/null @@ -1,90 +0,0 @@ -// 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.Reflection; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Components.Rendering; - -namespace Microsoft.AspNetCore.Components -{ - /// - /// Displays the specified page component, rendering it inside its layout - /// and any further nested layouts. - /// - public class RouteView : IComponent - { - private readonly RenderFragment _renderDelegate; - private readonly RenderFragment _renderPageWithParametersDelegate; - private RenderHandle _renderHandle; - - /// - /// Gets or sets the route data. This determines the page that will be - /// displayed and the parameter values that will be supplied to the page. - /// - [Parameter] - public RouteData RouteData { get; set; } - - /// - /// Gets or sets the type of a layout to be used if the page does not - /// declare any layout. If specified, the type must implement - /// and accept a parameter named . - /// - [Parameter] - public Type DefaultLayout { get; set; } - - public RouteView() - { - // Cache the delegate instances - _renderDelegate = Render; - _renderPageWithParametersDelegate = RenderPageWithParameters; - } - - /// - public void Attach(RenderHandle renderHandle) - { - _renderHandle = renderHandle; - } - - /// - public Task SetParametersAsync(ParameterView parameters) - { - parameters.SetParameterProperties(this); - - if (RouteData == null) - { - throw new InvalidOperationException($"The {nameof(RouteView)} component requires a non-null value for the parameter {nameof(RouteData)}."); - } - - _renderHandle.Render(_renderDelegate); - return Task.CompletedTask; - } - - /// - /// Renders the component. - /// - /// The . - protected virtual void Render(RenderTreeBuilder builder) - { - var pageLayoutType = RouteData.PageType.GetCustomAttribute()?.LayoutType - ?? DefaultLayout; - - builder.OpenComponent(0); - builder.AddAttribute(1, nameof(LayoutView.Layout), pageLayoutType); - builder.AddAttribute(2, nameof(LayoutView.ChildContent), _renderPageWithParametersDelegate); - builder.CloseComponent(); - } - - private void RenderPageWithParameters(RenderTreeBuilder builder) - { - builder.OpenComponent(0, RouteData.PageType); - - foreach (var kvp in RouteData.RouteValues) - { - builder.AddAttribute(1, kvp.Key, kvp.Value); - } - - builder.CloseComponent(); - } - } -} diff --git a/src/Components/Components/src/Routing/IHostEnvironmentNavigationManager.cs b/src/Components/Components/src/Routing/IHostEnvironmentNavigationManager.cs deleted file mode 100644 index 89dac06e0f..0000000000 --- a/src/Components/Components/src/Routing/IHostEnvironmentNavigationManager.cs +++ /dev/null @@ -1,19 +0,0 @@ -// 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. - -namespace Microsoft.AspNetCore.Components.Routing -{ - /// - /// An optional interface for implementations that must be initialized - /// by the host. - /// - public interface IHostEnvironmentNavigationManager - { - /// - /// Initializes the . - /// - /// The base URI. - /// The absolute URI. - void Initialize(string baseUri, string uri); - } -} diff --git a/src/Components/Components/src/Routing/INavigationInterception.cs b/src/Components/Components/src/Routing/INavigationInterception.cs deleted file mode 100644 index 0100062aba..0000000000 --- a/src/Components/Components/src/Routing/INavigationInterception.cs +++ /dev/null @@ -1,19 +0,0 @@ -// 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.Threading.Tasks; - -namespace Microsoft.AspNetCore.Components.Routing -{ - /// - /// Contract to setup navigation interception on the client. - /// - public interface INavigationInterception - { - /// - /// Enables navigation interception on the client. - /// - /// A that represents the asynchronous operation. - Task EnableNavigationInterceptionAsync(); - } -} diff --git a/src/Components/Components/src/Routing/LocationChangedEventArgs.cs b/src/Components/Components/src/Routing/LocationChangedEventArgs.cs deleted file mode 100644 index 7d1dca39e4..0000000000 --- a/src/Components/Components/src/Routing/LocationChangedEventArgs.cs +++ /dev/null @@ -1,34 +0,0 @@ -// 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.AspNetCore.Components.Routing -{ - /// - /// for . - /// - public class LocationChangedEventArgs : EventArgs - { - /// - /// Initializes a new instance of . - /// - /// The location. - /// A value that determines if navigation for the link was intercepted. - public LocationChangedEventArgs(string location, bool isNavigationIntercepted) - { - Location = location; - IsNavigationIntercepted = isNavigationIntercepted; - } - - /// - /// Gets the changed location. - /// - public string Location { get; } - - /// - /// Gets a value that determines if navigation for the link was intercepted. - /// - public bool IsNavigationIntercepted { get; } - } -} diff --git a/src/Components/Components/src/Routing/RouteConstraint.cs b/src/Components/Components/src/Routing/RouteConstraint.cs deleted file mode 100644 index c57180fb87..0000000000 --- a/src/Components/Components/src/Routing/RouteConstraint.cs +++ /dev/null @@ -1,81 +0,0 @@ -// 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.Collections.Concurrent; -using System.Globalization; - -namespace Microsoft.AspNetCore.Components.Routing -{ - internal abstract class RouteConstraint - { - // note: the things that prevent this cache from growing unbounded is that - // we're the only caller to this code path, and the fact that there are only - // 8 possible instances that we create. - // - // The values passed in here for parsing are always static text defined in route attributes. - private static readonly ConcurrentDictionary _cachedConstraints - = new ConcurrentDictionary(); - - public abstract bool Match(string pathSegment, out object convertedValue); - - public static RouteConstraint Parse(string template, string segment, string constraint) - { - if (string.IsNullOrEmpty(constraint)) - { - throw new ArgumentException($"Malformed segment '{segment}' in route '{template}' contains an empty constraint."); - } - - if (_cachedConstraints.TryGetValue(constraint, out var cachedInstance)) - { - return cachedInstance; - } - else - { - var newInstance = CreateRouteConstraint(constraint); - if (newInstance != null) - { - // We've done to the work to create the constraint now, but it's possible - // we're competing with another thread. GetOrAdd can ensure only a single - // instance is returned so that any extra ones can be GC'ed. - return _cachedConstraints.GetOrAdd(constraint, newInstance); - } - else - { - throw new ArgumentException($"Unsupported constraint '{constraint}' in route '{template}'."); - } - } - } - - private static RouteConstraint CreateRouteConstraint(string constraint) - { - switch (constraint) - { - case "bool": - return new TypeRouteConstraint(bool.TryParse); - case "datetime": - return new TypeRouteConstraint((string str, out DateTime result) - => DateTime.TryParse(str, CultureInfo.InvariantCulture, DateTimeStyles.None, out result)); - case "decimal": - return new TypeRouteConstraint((string str, out decimal result) - => decimal.TryParse(str, NumberStyles.Number, CultureInfo.InvariantCulture, out result)); - case "double": - return new TypeRouteConstraint((string str, out double result) - => double.TryParse(str, NumberStyles.Number, CultureInfo.InvariantCulture, out result)); - case "float": - return new TypeRouteConstraint((string str, out float result) - => float.TryParse(str, NumberStyles.Number, CultureInfo.InvariantCulture, out result)); - case "guid": - return new TypeRouteConstraint(Guid.TryParse); - case "int": - return new TypeRouteConstraint((string str, out int result) - => int.TryParse(str, NumberStyles.Integer, CultureInfo.InvariantCulture, out result)); - case "long": - return new TypeRouteConstraint((string str, out long result) - => long.TryParse(str, NumberStyles.Integer, CultureInfo.InvariantCulture, out result)); - default: - return null; - } - } - } -} diff --git a/src/Components/Components/src/Routing/RouteContext.cs b/src/Components/Components/src/Routing/RouteContext.cs deleted file mode 100644 index 7061e9be41..0000000000 --- a/src/Components/Components/src/Routing/RouteContext.cs +++ /dev/null @@ -1,31 +0,0 @@ -// 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.Collections.Generic; - -namespace Microsoft.AspNetCore.Components.Routing -{ - internal class RouteContext - { - private static char[] Separator = new[] { '/' }; - - public RouteContext(string path) - { - // This is a simplification. We are assuming there are no paths like /a//b/. A proper routing - // implementation would be more sophisticated. - Segments = path.Trim('/').Split(Separator, StringSplitOptions.RemoveEmptyEntries); - // Individual segments are URL-decoded in order to support arbitrary characters, assuming UTF-8 encoding. - for (int i = 0; i < Segments.Length; i++) - { - Segments[i] = Uri.UnescapeDataString(Segments[i]); - } - } - - public string[] Segments { get; } - - public Type Handler { get; set; } - - public IReadOnlyDictionary Parameters { get; set; } - } -} diff --git a/src/Components/Components/src/Routing/RouteData.cs b/src/Components/Components/src/Routing/RouteData.cs deleted file mode 100644 index e0da00f0c7..0000000000 --- a/src/Components/Components/src/Routing/RouteData.cs +++ /dev/null @@ -1,46 +0,0 @@ -// 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.Collections.Generic; - -namespace Microsoft.AspNetCore.Components -{ - /// - /// Describes information determined during routing that specifies - /// the page to be displayed. - /// - public sealed class RouteData - { - /// - /// Constructs an instance of . - /// - /// The type of the page matching the route, which must implement . - /// The route parameter values extracted from the matched route. - public RouteData(Type pageType, IReadOnlyDictionary routeValues) - { - if (pageType == null) - { - throw new ArgumentNullException(nameof(pageType)); - } - - if (!typeof(IComponent).IsAssignableFrom(pageType)) - { - throw new ArgumentException($"The value must implement {nameof(IComponent)}.", nameof(pageType)); - } - - PageType = pageType; - RouteValues = routeValues ?? throw new ArgumentNullException(nameof(routeValues)); - } - - /// - /// Gets the type of the page matching the route. - /// - public Type PageType { get; } - - /// - /// Gets route parameter values extracted from the matched route. - /// - public IReadOnlyDictionary RouteValues { get; } - } -} diff --git a/src/Components/Components/src/Routing/RouteEntry.cs b/src/Components/Components/src/Routing/RouteEntry.cs deleted file mode 100644 index d2bca6d2a7..0000000000 --- a/src/Components/Components/src/Routing/RouteEntry.cs +++ /dev/null @@ -1,69 +0,0 @@ -// 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.Collections.Generic; -using System.Diagnostics; - -namespace Microsoft.AspNetCore.Components.Routing -{ - [DebuggerDisplay("Handler = {Handler}, Template = {Template}")] - internal class RouteEntry - { - public RouteEntry(RouteTemplate template, Type handler, string[] unusedRouteParameterNames) - { - Template = template; - UnusedRouteParameterNames = unusedRouteParameterNames; - Handler = handler; - } - - public RouteTemplate Template { get; } - - public string[] UnusedRouteParameterNames { get; } - - public Type Handler { get; } - - internal void Match(RouteContext context) - { - if (Template.Segments.Length != context.Segments.Length) - { - return; - } - - // Parameters will be lazily initialized. - Dictionary parameters = null; - for (var i = 0; i < Template.Segments.Length; i++) - { - var segment = Template.Segments[i]; - var pathSegment = context.Segments[i]; - if (!segment.Match(pathSegment, out var matchedParameterValue)) - { - return; - } - else - { - if (segment.IsParameter) - { - parameters ??= new Dictionary(StringComparer.Ordinal); - parameters[segment.Value] = matchedParameterValue; - } - } - } - - // In addition to extracting parameter values from the URL, each route entry - // also knows which other parameters should be supplied with null values. These - // are parameters supplied by other route entries matching the same handler. - if (UnusedRouteParameterNames.Length > 0) - { - parameters ??= new Dictionary(StringComparer.Ordinal); - for (var i = 0; i < UnusedRouteParameterNames.Length; i++) - { - parameters[UnusedRouteParameterNames[i]] = null; - } - } - - context.Parameters = parameters; - context.Handler = Handler; - } - } -} diff --git a/src/Components/Components/src/Routing/RouteTable.cs b/src/Components/Components/src/Routing/RouteTable.cs deleted file mode 100644 index 029bc47657..0000000000 --- a/src/Components/Components/src/Routing/RouteTable.cs +++ /dev/null @@ -1,27 +0,0 @@ -// 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. - -namespace Microsoft.AspNetCore.Components.Routing -{ - internal class RouteTable - { - public RouteTable(RouteEntry[] routes) - { - Routes = routes; - } - - public RouteEntry[] Routes { get; } - - internal void Route(RouteContext routeContext) - { - for (var i = 0; i < Routes.Length; i++) - { - Routes[i].Match(routeContext); - if (routeContext.Handler != null) - { - return; - } - } - } - } -} diff --git a/src/Components/Components/src/Routing/RouteTableFactory.cs b/src/Components/Components/src/Routing/RouteTableFactory.cs deleted file mode 100644 index de6fe31c1d..0000000000 --- a/src/Components/Components/src/Routing/RouteTableFactory.cs +++ /dev/null @@ -1,227 +0,0 @@ -// 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.Collections.Concurrent; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using Microsoft.AspNetCore.Components.Routing; -using Microsoft.Extensions.Internal; - -namespace Microsoft.AspNetCore.Components -{ - /// - /// Resolves components for an application. - /// - internal static class RouteTableFactory - { - private static readonly ConcurrentDictionary Cache = - new ConcurrentDictionary(); - public static readonly IComparer RoutePrecedence = Comparer.Create(RouteComparison); - - public static RouteTable Create(IEnumerable assemblies) - { - var key = new Key(assemblies.OrderBy(a => a.FullName).ToArray()); - if (Cache.TryGetValue(key, out var resolvedComponents)) - { - return resolvedComponents; - } - - var componentTypes = key.Assemblies.SelectMany(a => a.ExportedTypes.Where(t => typeof(IComponent).IsAssignableFrom(t))); - var routeTable = Create(componentTypes); - Cache.TryAdd(key, routeTable); - return routeTable; - } - - internal static RouteTable Create(IEnumerable componentTypes) - { - var templatesByHandler = new Dictionary(); - foreach (var componentType in componentTypes) - { - // We're deliberately using inherit = false here. - // - // RouteAttribute is defined as non-inherited, because inheriting a route attribute always causes an - // ambiguity. You end up with two components (base class and derived class) with the same route. - var routeAttributes = componentType.GetCustomAttributes(inherit: false); - - var templates = routeAttributes.Select(t => t.Template).ToArray(); - templatesByHandler.Add(componentType, templates); - } - return Create(templatesByHandler); - } - - internal static RouteTable Create(Dictionary templatesByHandler) - { - var routes = new List(); - foreach (var keyValuePair in templatesByHandler) - { - var parsedTemplates = keyValuePair.Value.Select(v => TemplateParser.ParseTemplate(v)).ToArray(); - var allRouteParameterNames = parsedTemplates - .SelectMany(GetParameterNames) - .Distinct(StringComparer.OrdinalIgnoreCase) - .ToArray(); - - foreach (var parsedTemplate in parsedTemplates) - { - var unusedRouteParameterNames = allRouteParameterNames - .Except(GetParameterNames(parsedTemplate), StringComparer.OrdinalIgnoreCase) - .ToArray(); - var entry = new RouteEntry(parsedTemplate, keyValuePair.Key, unusedRouteParameterNames); - routes.Add(entry); - } - } - - return new RouteTable(routes.OrderBy(id => id, RoutePrecedence).ToArray()); - } - - private static string[] GetParameterNames(RouteTemplate routeTemplate) - { - return routeTemplate.Segments - .Where(s => s.IsParameter) - .Select(s => s.Value) - .ToArray(); - } - - /// - /// Route precedence algorithm. - /// We collect all the routes and sort them from most specific to - /// less specific. The specificity of a route is given by the specificity - /// of its segments and the position of those segments in the route. - /// * A literal segment is more specific than a parameter segment. - /// * A parameter segment with more constraints is more specific than one with fewer constraints - /// * Segment earlier in the route are evaluated before segments later in the route. - /// For example: - /// /Literal is more specific than /Parameter - /// /Route/With/{parameter} is more specific than /{multiple}/With/{parameters} - /// /Product/{id:int} is more specific than /Product/{id} - /// - /// Routes can be ambiguous if: - /// They are composed of literals and those literals have the same values (case insensitive) - /// They are composed of a mix of literals and parameters, in the same relative order and the - /// literals have the same values. - /// For example: - /// * /literal and /Literal - /// /{parameter}/literal and /{something}/literal - /// /{parameter:constraint}/literal and /{something:constraint}/literal - /// - /// To calculate the precedence we sort the list of routes as follows: - /// * Shorter routes go first. - /// * A literal wins over a parameter in precedence. - /// * For literals with different values (case insensitive) we choose the lexical order - /// * For parameters with different numbers of constraints, the one with more wins - /// If we get to the end of the comparison routing we've detected an ambiguous pair of routes. - /// - internal static int RouteComparison(RouteEntry x, RouteEntry y) - { - if (ReferenceEquals(x, y)) - { - return 0; - } - - var xTemplate = x.Template; - var yTemplate = y.Template; - if (xTemplate.Segments.Length != y.Template.Segments.Length) - { - return xTemplate.Segments.Length < y.Template.Segments.Length ? -1 : 1; - } - else - { - for (var i = 0; i < xTemplate.Segments.Length; i++) - { - var xSegment = xTemplate.Segments[i]; - var ySegment = yTemplate.Segments[i]; - if (!xSegment.IsParameter && ySegment.IsParameter) - { - return -1; - } - if (xSegment.IsParameter && !ySegment.IsParameter) - { - return 1; - } - - if (xSegment.IsParameter) - { - if (xSegment.Constraints.Length > ySegment.Constraints.Length) - { - return -1; - } - else if (xSegment.Constraints.Length < ySegment.Constraints.Length) - { - return 1; - } - } - else - { - var comparison = string.Compare(xSegment.Value, ySegment.Value, StringComparison.OrdinalIgnoreCase); - if (comparison != 0) - { - return comparison; - } - } - } - - throw new InvalidOperationException($@"The following routes are ambiguous: -'{x.Template.TemplateText}' in '{x.Handler.FullName}' -'{y.Template.TemplateText}' in '{y.Handler.FullName}' -"); - } - } - - private readonly struct Key : IEquatable - { - public readonly Assembly[] Assemblies; - - public Key(Assembly[] assemblies) - { - Assemblies = assemblies; - } - - public override bool Equals(object obj) - { - return obj is Key other ? base.Equals(other) : false; - } - - public bool Equals(Key other) - { - if (Assemblies == null && other.Assemblies == null) - { - return true; - } - else if (Assemblies == null ^ other.Assemblies == null) - { - return false; - } - else if (Assemblies.Length != other.Assemblies.Length) - { - return false; - } - - for (var i = 0; i < Assemblies.Length; i++) - { - if (!Assemblies[i].Equals(other.Assemblies[i])) - { - return false; - } - } - - return true; - } - - public override int GetHashCode() - { - var hash = new HashCodeCombiner(); - - if (Assemblies != null) - { - for (var i = 0; i < Assemblies.Length; i++) - { - hash.Add(Assemblies[i]); - } - } - - return hash; - } - } - } -} diff --git a/src/Components/Components/src/Routing/RouteTemplate.cs b/src/Components/Components/src/Routing/RouteTemplate.cs deleted file mode 100644 index a79f0f911a..0000000000 --- a/src/Components/Components/src/Routing/RouteTemplate.cs +++ /dev/null @@ -1,22 +0,0 @@ -// 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.Diagnostics; - -namespace Microsoft.AspNetCore.Components.Routing -{ - [DebuggerDisplay("{TemplateText}")] - internal class RouteTemplate - { - public RouteTemplate(string templateText, TemplateSegment[] segments) - { - TemplateText = templateText; - Segments = segments; - } - - public string TemplateText { get; } - - public TemplateSegment[] Segments { get; } - } -} diff --git a/src/Components/Components/src/Routing/Router.cs b/src/Components/Components/src/Routing/Router.cs deleted file mode 100644 index b93db4b6ac..0000000000 --- a/src/Components/Components/src/Routing/Router.cs +++ /dev/null @@ -1,203 +0,0 @@ -// 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.Collections.Generic; -using System.Collections.ObjectModel; -using System.Linq; -using System.Reflection; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Components.Rendering; -using Microsoft.Extensions.Logging; - -namespace Microsoft.AspNetCore.Components.Routing -{ - /// - /// A component that supplies route data corresponding to the current navigation state. - /// - public class Router : IComponent, IHandleAfterRender, IDisposable - { - static readonly char[] _queryOrHashStartChar = new[] { '?', '#' }; - static readonly ReadOnlyDictionary _emptyParametersDictionary - = new ReadOnlyDictionary(new Dictionary()); - - RenderHandle _renderHandle; - string _baseUri; - string _locationAbsolute; - bool _navigationInterceptionEnabled; - ILogger _logger; - - [Inject] private NavigationManager NavigationManager { get; set; } - - [Inject] private INavigationInterception NavigationInterception { get; set; } - - [Inject] private ILoggerFactory LoggerFactory { get; set; } - - /// - /// Gets or sets the assembly that should be searched for components matching the URI. - /// - [Parameter] public Assembly AppAssembly { get; set; } - - /// - /// Gets or sets a collection of additional assemblies that should be searched for components - /// that can match URIs. - /// - [Parameter] public IEnumerable AdditionalAssemblies { get; set; } - - /// - /// Gets or sets the content to display when no match is found for the requested route. - /// - [Parameter] public RenderFragment NotFound { get; set; } - - /// - /// Gets or sets the content to display when a match is found for the requested route. - /// - [Parameter] public RenderFragment Found { get; set; } - - private RouteTable Routes { get; set; } - - /// - public void Attach(RenderHandle renderHandle) - { - _logger = LoggerFactory.CreateLogger(); - _renderHandle = renderHandle; - _baseUri = NavigationManager.BaseUri; - _locationAbsolute = NavigationManager.Uri; - NavigationManager.LocationChanged += OnLocationChanged; - } - - /// - public Task SetParametersAsync(ParameterView parameters) - { - parameters.SetParameterProperties(this); - - if (AppAssembly == null) - { - throw new InvalidOperationException($"The {nameof(Router)} component requires a value for the parameter {nameof(AppAssembly)}."); - } - - // Found content is mandatory, because even though we could use something like as a - // reasonable default, if it's not declared explicitly in the template then people will have no way - // to discover how to customize this (e.g., to add authorization). - if (Found == null) - { - throw new InvalidOperationException($"The {nameof(Router)} component requires a value for the parameter {nameof(Found)}."); - } - - // NotFound content is mandatory, because even though we could display a default message like "Not found", - // it has to be specified explicitly so that it can also be wrapped in a specific layout - if (NotFound == null) - { - throw new InvalidOperationException($"The {nameof(Router)} component requires a value for the parameter {nameof(NotFound)}."); - } - - - var assemblies = AdditionalAssemblies == null ? new[] { AppAssembly } : new[] { AppAssembly }.Concat(AdditionalAssemblies); - Routes = RouteTableFactory.Create(assemblies); - Refresh(isNavigationIntercepted: false); - return Task.CompletedTask; - } - - /// - public void Dispose() - { - NavigationManager.LocationChanged -= OnLocationChanged; - } - - private static string StringUntilAny(string str, char[] chars) - { - var firstIndex = str.IndexOfAny(chars); - return firstIndex < 0 - ? str - : str.Substring(0, firstIndex); - } - - private void Refresh(bool isNavigationIntercepted) - { - var locationPath = NavigationManager.ToBaseRelativePath(_locationAbsolute); - locationPath = StringUntilAny(locationPath, _queryOrHashStartChar); - var context = new RouteContext(locationPath); - Routes.Route(context); - - if (context.Handler != null) - { - if (!typeof(IComponent).IsAssignableFrom(context.Handler)) - { - throw new InvalidOperationException($"The type {context.Handler.FullName} " + - $"does not implement {typeof(IComponent).FullName}."); - } - - Log.NavigatingToComponent(_logger, context.Handler, locationPath, _baseUri); - - var routeData = new RouteData( - context.Handler, - context.Parameters ?? _emptyParametersDictionary); - _renderHandle.Render(Found(routeData)); - } - else - { - if (!isNavigationIntercepted) - { - Log.DisplayingNotFound(_logger, locationPath, _baseUri); - - // We did not find a Component that matches the route. - // Only show the NotFound content if the application developer programatically got us here i.e we did not - // intercept the navigation. In all other cases, force a browser navigation since this could be non-Blazor content. - _renderHandle.Render(NotFound); - } - else - { - Log.NavigatingToExternalUri(_logger, _locationAbsolute, locationPath, _baseUri); - NavigationManager.NavigateTo(_locationAbsolute, forceLoad: true); - } - } - } - - private void OnLocationChanged(object sender, LocationChangedEventArgs args) - { - _locationAbsolute = args.Location; - if (_renderHandle.IsInitialized && Routes != null) - { - Refresh(args.IsNavigationIntercepted); - } - } - - Task IHandleAfterRender.OnAfterRenderAsync() - { - if (!_navigationInterceptionEnabled) - { - _navigationInterceptionEnabled = true; - return NavigationInterception.EnableNavigationInterceptionAsync(); - } - - return Task.CompletedTask; - } - - private static class Log - { - private static readonly Action _displayingNotFound = - LoggerMessage.Define(LogLevel.Debug, new EventId(1, "DisplayingNotFound"), $"Displaying {nameof(NotFound)} because path '{{Path}}' with base URI '{{BaseUri}}' does not match any component route"); - - private static readonly Action _navigatingToComponent = - LoggerMessage.Define(LogLevel.Debug, new EventId(2, "NavigatingToComponent"), "Navigating to component {ComponentType} in response to path '{Path}' with base URI '{BaseUri}'"); - - private static readonly Action _navigatingToExternalUri = - LoggerMessage.Define(LogLevel.Debug, new EventId(3, "NavigatingToExternalUri"), "Navigating to non-component URI '{ExternalUri}' in response to path '{Path}' with base URI '{BaseUri}'"); - - internal static void DisplayingNotFound(ILogger logger, string path, string baseUri) - { - _displayingNotFound(logger, path, baseUri, null); - } - - internal static void NavigatingToComponent(ILogger logger, Type componentType, string path, string baseUri) - { - _navigatingToComponent(logger, componentType, path, baseUri, null); - } - - internal static void NavigatingToExternalUri(ILogger logger, string externalUri, string path, string baseUri) - { - _navigatingToExternalUri(logger, externalUri, path, baseUri, null); - } - } - } -} diff --git a/src/Components/Components/src/Routing/TemplateParser.cs b/src/Components/Components/src/Routing/TemplateParser.cs deleted file mode 100644 index d4563ebf7f..0000000000 --- a/src/Components/Components/src/Routing/TemplateParser.cs +++ /dev/null @@ -1,108 +0,0 @@ -// 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.AspNetCore.Components.Routing -{ - // This implementation is temporary, in the future we'll want to have - // a more performant/properly designed routing set of abstractions. - // To be more precise these are some things we are scoping out: - // * We are not doing link generation. - // * We are not supporting all the route constraint formats supported by ASP.NET server-side routing. - // The class in here just takes care of parsing a route and extracting - // simple parameters from it. - // Some differences with ASP.NET Core routes are: - // * We don't support catch all parameter segments. - // * We don't support optional parameter segments. - // * We don't support complex segments. - // The things that we support are: - // * Literal path segments. (Like /Path/To/Some/Page) - // * Parameter path segments (Like /Customer/{Id}/Orders/{OrderId}) - internal class TemplateParser - { - public static readonly char[] InvalidParameterNameCharacters = - new char[] { '*', '?', '{', '}', '=', '.' }; - - internal static RouteTemplate ParseTemplate(string template) - { - var originalTemplate = template; - template = template.Trim('/'); - if (template == "") - { - // Special case "/"; - return new RouteTemplate("/", Array.Empty()); - } - - var segments = template.Split('/'); - var templateSegments = new TemplateSegment[segments.Length]; - for (int i = 0; i < segments.Length; i++) - { - var segment = segments[i]; - if (string.IsNullOrEmpty(segment)) - { - throw new InvalidOperationException( - $"Invalid template '{template}'. Empty segments are not allowed."); - } - - if (segment[0] != '{') - { - if (segment[segment.Length - 1] == '}') - { - throw new InvalidOperationException( - $"Invalid template '{template}'. Missing '{{' in parameter segment '{segment}'."); - } - templateSegments[i] = new TemplateSegment(originalTemplate, segment, isParameter: false); - } - else - { - if (segment[segment.Length - 1] != '}') - { - throw new InvalidOperationException( - $"Invalid template '{template}'. Missing '}}' in parameter segment '{segment}'."); - } - - if (segment.Length < 3) - { - throw new InvalidOperationException( - $"Invalid template '{template}'. Empty parameter name in segment '{segment}' is not allowed."); - } - - var invalidCharacter = segment.IndexOfAny(InvalidParameterNameCharacters, 1, segment.Length - 2); - if (invalidCharacter != -1) - { - throw new InvalidOperationException( - $"Invalid template '{template}'. The character '{segment[invalidCharacter]}' in parameter segment '{segment}' is not allowed."); - } - - templateSegments[i] = new TemplateSegment(originalTemplate, segment.Substring(1, segment.Length - 2), isParameter: true); - } - } - - for (int i = 0; i < templateSegments.Length; i++) - { - var currentSegment = templateSegments[i]; - if (!currentSegment.IsParameter) - { - continue; - } - - for (int j = i + 1; j < templateSegments.Length; j++) - { - var nextSegment = templateSegments[j]; - if (!nextSegment.IsParameter) - { - continue; - } - - if (string.Equals(currentSegment.Value, nextSegment.Value, StringComparison.OrdinalIgnoreCase)) - { - throw new InvalidOperationException( - $"Invalid template '{template}'. The parameter '{currentSegment}' appears multiple times."); - } - } - } - - return new RouteTemplate(template, templateSegments); - } - } -} diff --git a/src/Components/Components/src/Routing/TemplateSegment.cs b/src/Components/Components/src/Routing/TemplateSegment.cs deleted file mode 100644 index 9f732598db..0000000000 --- a/src/Components/Components/src/Routing/TemplateSegment.cs +++ /dev/null @@ -1,66 +0,0 @@ -// 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.Linq; - -namespace Microsoft.AspNetCore.Components.Routing -{ - internal class TemplateSegment - { - public TemplateSegment(string template, string segment, bool isParameter) - { - IsParameter = isParameter; - - if (!isParameter || segment.IndexOf(':') < 0) - { - Value = segment; - Constraints = Array.Empty(); - } - else - { - var tokens = segment.Split(':'); - if (tokens[0].Length == 0) - { - throw new ArgumentException($"Malformed parameter '{segment}' in route '{template}' has no name before the constraints list."); - } - - Value = tokens[0]; - Constraints = tokens.Skip(1) - .Select(token => RouteConstraint.Parse(template, segment, token)) - .ToArray(); - } - } - - // The value of the segment. The exact text to match when is a literal. - // The parameter name when its a segment - public string Value { get; } - - public bool IsParameter { get; } - - public RouteConstraint[] Constraints { get; } - - public bool Match(string pathSegment, out object matchedParameterValue) - { - if (IsParameter) - { - matchedParameterValue = pathSegment; - - foreach (var constraint in Constraints) - { - if (!constraint.Match(pathSegment, out matchedParameterValue)) - { - return false; - } - } - - return true; - } - else - { - matchedParameterValue = null; - return string.Equals(Value, pathSegment, StringComparison.OrdinalIgnoreCase); - } - } - } -} diff --git a/src/Components/Components/src/Routing/TypeRouteConstraint.cs b/src/Components/Components/src/Routing/TypeRouteConstraint.cs deleted file mode 100644 index 1026e88eac..0000000000 --- a/src/Components/Components/src/Routing/TypeRouteConstraint.cs +++ /dev/null @@ -1,35 +0,0 @@ -// 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. - -namespace Microsoft.AspNetCore.Components.Routing -{ - /// - /// A route constraint that requires the value to be parseable as a specified type. - /// - /// The type to which the value must be parseable. - internal class TypeRouteConstraint : RouteConstraint - { - public delegate bool TryParseDelegate(string str, out T result); - - private readonly TryParseDelegate _parser; - - public TypeRouteConstraint(TryParseDelegate parser) - { - _parser = parser; - } - - public override bool Match(string pathSegment, out object convertedValue) - { - if (_parser(pathSegment, out var result)) - { - convertedValue = result; - return true; - } - else - { - convertedValue = null; - return false; - } - } - } -} diff --git a/src/Components/Components/test/BindConverterTest.cs b/src/Components/Components/test/BindConverterTest.cs deleted file mode 100644 index c6fe1275cc..0000000000 --- a/src/Components/Components/test/BindConverterTest.cs +++ /dev/null @@ -1,307 +0,0 @@ -// 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.ComponentModel; -using System.Diagnostics; -using System.Globalization; -using System.Text.Json; -using Xunit; - -namespace Microsoft.AspNetCore.Components -{ - // This is some basic coverage, it's not in depth because there are many many APIs here - // and they mostly call through to CoreFx. We don't want to test the globalization details - // of .NET in detail where we can avoid it. - // - // Instead there's a sampling of things that have somewhat unique behavior or semantics. - public class BindConverterTest - { - [Fact] - public void FormatValue_Bool() - { - // Arrange - var value = true; - var expected = true; - - // Act - var actual = BindConverter.FormatValue(value); - - // Assert - Assert.Equal(expected, actual); - } - - [Fact] - public void FormatValue_Bool_Generic() - { - // Arrange - var value = true; - var expected = true; - - // Act - var actual = BindConverter.FormatValue(value); - - // Assert - Assert.Equal(expected, actual); - } - - [Fact] - public void FormatValue_NullableBool() - { - // Arrange - var value = (bool?)true; - var expected = true; - - // Act - var actual = BindConverter.FormatValue(value); - - // Assert - Assert.Equal(expected, actual); - } - - [Fact] - public void FormatValue_NullableBool_Generic() - { - // Arrange - var value = true; - var expected = true; - - // Act - var actual = BindConverter.FormatValue(value); - - // Assert - Assert.Equal(expected, actual); - } - - [Fact] - public void FormatValue_NullableBoolNull() - { - // Arrange - var value = (bool?)null; - var expected = (bool?)null; - - // Act - var actual = BindConverter.FormatValue(value); - - // Assert - Assert.Equal(expected, actual); - } - - [Fact] - public void FormatValue_NullableBoolNull_Generic() - { - // Arrange - var value = (bool?)null; - var expected = (bool?)null; - - // Act - var actual = BindConverter.FormatValue(value); - - // Assert - Assert.Equal(expected, actual); - } - - [Fact] - public void FormatValue_Int() - { - // Arrange - var value = 17; - var expected = "17"; - - // Act - var actual = BindConverter.FormatValue(value); - - // Assert - Assert.Equal(expected, actual); - } - - [Fact] - public void FormatValue_Int_Generic() - { - // Arrange - var value = 17; - var expected = "17"; - - // Act - var actual = BindConverter.FormatValue(value); - - // Assert - Assert.Equal(expected, actual); - } - - [Fact] - public void FormatValue_NullableInt() - { - // Arrange - var value = (int?)17; - var expected = "17"; - - // Act - var actual = BindConverter.FormatValue(value); - - // Assert - Assert.Equal(expected, actual); - } - - [Fact] - public void FormatValue_NullableInt_Generic() - { - // Arrange - var value = 17; - var expected = "17"; - - // Act - var actual = BindConverter.FormatValue(value); - - // Assert - Assert.Equal(expected, actual); - } - - [Fact] - public void FormatValue_DateTime() - { - // Arrange - var value = DateTime.Now; - var expected = value.ToString(CultureInfo.CurrentCulture); - - // Act - var actual = BindConverter.FormatValue(value); - - // Assert - Assert.Equal(expected, actual); - } - - [Fact] - public void FormatValue_DateTime_Format() - { - // Arrange - var value = DateTime.Now; - var expected = value.ToString("MM-yyyy", CultureInfo.InvariantCulture); - - // Act - var actual = BindConverter.FormatValue(value, "MM-yyyy", CultureInfo.InvariantCulture); - - // Assert - Assert.Equal(expected, actual); - } - - [Fact] - public void FormatValue_Enum() - { - // Arrange - var value = SomeLetters.A; - var expected = value.ToString(); - - // Act - var actual = BindConverter.FormatValue(value); - - // Assert - Assert.Equal(expected, actual); - } - - [Fact] - public void FormatValue_Enum_OutOfRange() - { - // Arrange - var value = SomeLetters.A + 3; - var expected = value.ToString(); - - // Act - var actual = BindConverter.FormatValue(value); - - // Assert - Assert.Equal(expected, actual); - } - - [Fact] - public void FormatValue_NullableEnum() - { - // Arrange - var value = (SomeLetters?)null; - - // Act - var actual = BindConverter.FormatValue(value); - - // Assert - Assert.Null(actual); - } - - [Fact] - public void FormatValue_TypeConverter() - { - // Arrange - var value = new Person() - { - Name = "Glenn", - Age = 47, - }; - - var expected = JsonSerializer.Serialize(value); - - // Act - var actual = BindConverter.FormatValue(value); - - // Assert - Assert.Equal(expected, actual); - } - - private enum SomeLetters - { - A, - B, - C, - Q, - } - - [TypeConverter(typeof(PersonConverter))] - private class Person - { - public string Name { get; set; } - - public int Age { get; set; } - } - - private class PersonConverter : TypeConverter - { - public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) - { - if (sourceType == typeof(string)) - { - return true; - } - - return base.CanConvertFrom(context, sourceType); - } - - public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) - { - if (value is string text) - { - return JsonSerializer.Deserialize(text); - } - - return base.ConvertFrom(context, culture, value); - } - - public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) - { - if (destinationType == typeof(string)) - { - return true; - } - - return base.CanConvertTo(context, destinationType); - } - - public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) - { - if (destinationType == typeof(string)) - { - return JsonSerializer.Serialize((Person)value); - } - - return base.ConvertTo(context, culture, value, destinationType); - } - } - } -} diff --git a/src/Components/Components/test/CascadingParameterStateTest.cs b/src/Components/Components/test/CascadingParameterStateTest.cs deleted file mode 100644 index 5931d9d6fc..0000000000 --- a/src/Components/Components/test/CascadingParameterStateTest.cs +++ /dev/null @@ -1,442 +0,0 @@ -// 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.AspNetCore.Components; -using Microsoft.AspNetCore.Components.Rendering; -using Microsoft.AspNetCore.Components.Test.Helpers; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Xunit; - -namespace Microsoft.AspNetCore.Components.Test -{ - public class CascadingParameterStateTest - { - [Fact] - public void FindCascadingParameters_IfHasNoParameters_ReturnsNull() - { - // Arrange - var componentState = CreateComponentState(new ComponentWithNoParams()); - - // Act - var result = CascadingParameterState.FindCascadingParameters(componentState); - - // Assert - Assert.Null(result); - } - - [Fact] - public void FindCascadingParameters_IfHasNoCascadingParameters_ReturnsNull() - { - // Arrange - var componentState = CreateComponentState(new ComponentWithNoCascadingParams()); - - // Act - var result = CascadingParameterState.FindCascadingParameters(componentState); - - // Assert - Assert.Null(result); - } - - [Fact] - public void FindCascadingParameters_IfHasNoAncestors_ReturnsNull() - { - // Arrange - var componentState = CreateComponentState(new ComponentWithCascadingParams()); - - // Act - var result = CascadingParameterState.FindCascadingParameters(componentState); - - // Assert - Assert.Null(result); - } - - [Fact] - public void FindCascadingParameters_IfHasNoMatchesInAncestors_ReturnsNull() - { - // Arrange: Build the ancestry list - var states = CreateAncestry( - new ComponentWithNoParams(), - CreateCascadingValueComponent("Hello"), - new ComponentWithNoParams(), - new ComponentWithCascadingParams()); - - // Act - var result = CascadingParameterState.FindCascadingParameters(states.Last()); - - // Assert - Assert.Null(result); - } - - [Fact] - public void FindCascadingParameters_IfHasPartialMatchesInAncestors_ReturnsMatches() - { - // Arrange - var states = CreateAncestry( - new ComponentWithNoParams(), - CreateCascadingValueComponent(new ValueType2()), - new ComponentWithNoParams(), - new ComponentWithCascadingParams()); - - // Act - var result = CascadingParameterState.FindCascadingParameters(states.Last()); - - // Assert - Assert.Collection(result, match => - { - Assert.Equal(nameof(ComponentWithCascadingParams.CascadingParam2), match.LocalValueName); - Assert.Same(states[1].Component, match.ValueSupplier); - }); - } - - [Fact] - public void FindCascadingParameters_IfHasMultipleMatchesInAncestors_ReturnsMatches() - { - // Arrange - var states = CreateAncestry( - new ComponentWithNoParams(), - CreateCascadingValueComponent(new ValueType2()), - new ComponentWithNoParams(), - CreateCascadingValueComponent(new ValueType1()), - new ComponentWithCascadingParams()); - - // Act - var result = CascadingParameterState.FindCascadingParameters(states.Last()); - - // Assert - Assert.Collection(result.OrderBy(x => x.LocalValueName), - match => { - Assert.Equal(nameof(ComponentWithCascadingParams.CascadingParam1), match.LocalValueName); - Assert.Same(states[3].Component, match.ValueSupplier); - }, - match => { - Assert.Equal(nameof(ComponentWithCascadingParams.CascadingParam2), match.LocalValueName); - Assert.Same(states[1].Component, match.ValueSupplier); - }); - } - - [Fact] - public void FindCascadingParameters_InheritedParameters_ReturnsMatches() - { - // Arrange - var states = CreateAncestry( - CreateCascadingValueComponent(new ValueType1()), - CreateCascadingValueComponent(new ValueType3()), - new ComponentWithInheritedCascadingParams()); - - // Act - var result = CascadingParameterState.FindCascadingParameters(states.Last()); - - // Assert - Assert.Collection(result.OrderBy(x => x.LocalValueName), - match => { - Assert.Equal(nameof(ComponentWithCascadingParams.CascadingParam1), match.LocalValueName); - Assert.Same(states[0].Component, match.ValueSupplier); - }, - match => { - Assert.Equal(nameof(ComponentWithInheritedCascadingParams.CascadingParam3), match.LocalValueName); - Assert.Same(states[1].Component, match.ValueSupplier); - }); - } - - [Fact] - public void FindCascadingParameters_ComponentRequestsBaseType_ReturnsMatches() - { - // Arrange - var states = CreateAncestry( - CreateCascadingValueComponent(new CascadingValueTypeDerivedClass()), - new ComponentWithGenericCascadingParam()); - - // Act - var result = CascadingParameterState.FindCascadingParameters(states.Last()); - - // Assert - Assert.Collection(result, match => { - Assert.Equal(nameof(ComponentWithGenericCascadingParam.LocalName), match.LocalValueName); - Assert.Same(states[0].Component, match.ValueSupplier); - }); - } - - [Fact] - public void FindCascadingParameters_ComponentRequestsImplementedInterface_ReturnsMatches() - { - // Arrange - var states = CreateAncestry( - CreateCascadingValueComponent(new CascadingValueTypeDerivedClass()), - new ComponentWithGenericCascadingParam()); - - // Act - var result = CascadingParameterState.FindCascadingParameters(states.Last()); - - // Assert - Assert.Collection(result, match => { - Assert.Equal(nameof(ComponentWithGenericCascadingParam.LocalName), match.LocalValueName); - Assert.Same(states[0].Component, match.ValueSupplier); - }); - } - - [Fact] - public void FindCascadingParameters_ComponentRequestsDerivedType_ReturnsNull() - { - // Arrange - var states = CreateAncestry( - CreateCascadingValueComponent(new CascadingValueTypeBaseClass()), - new ComponentWithGenericCascadingParam()); - - // Act - var result = CascadingParameterState.FindCascadingParameters(states.Last()); - - // Assert - Assert.Null(result); - } - - [Fact] - public void FindCascadingParameters_TypeAssignmentIsValidForNullValue_ReturnsMatches() - { - // Arrange - var states = CreateAncestry( - CreateCascadingValueComponent((CascadingValueTypeDerivedClass)null), - new ComponentWithGenericCascadingParam()); - - // Act - var result = CascadingParameterState.FindCascadingParameters(states.Last()); - - // Assert - Assert.Collection(result, match => { - Assert.Equal(nameof(ComponentWithGenericCascadingParam.LocalName), match.LocalValueName); - Assert.Same(states[0].Component, match.ValueSupplier); - }); - } - - [Fact] - public void FindCascadingParameters_TypeAssignmentIsInvalidForNullValue_ReturnsNull() - { - // Arrange - var states = CreateAncestry( - CreateCascadingValueComponent((object)null), - new ComponentWithGenericCascadingParam()); - - // Act - var result = CascadingParameterState.FindCascadingParameters(states.Last()); - - // Assert - Assert.Null(result); - } - - [Fact] - public void FindCascadingParameters_SupplierSpecifiesNameButConsumerDoesNot_ReturnsNull() - { - // Arrange - var states = CreateAncestry( - CreateCascadingValueComponent(new ValueType1(), "MatchOnName"), - new ComponentWithCascadingParams()); - - // Act - var result = CascadingParameterState.FindCascadingParameters(states.Last()); - - // Assert - Assert.Null(result); - } - - [Fact] - public void FindCascadingParameters_ConsumerSpecifiesNameButSupplierDoesNot_ReturnsNull() - { - // Arrange - var states = CreateAncestry( - CreateCascadingValueComponent(new ValueType1()), - new ComponentWithNamedCascadingParam()); - - // Act - var result = CascadingParameterState.FindCascadingParameters(states.Last()); - - // Assert - Assert.Null(result); - } - - [Fact] - public void FindCascadingParameters_MismatchingNameButMatchingType_ReturnsNull() - { - // Arrange - var states = CreateAncestry( - CreateCascadingValueComponent(new ValueType1(), "MismatchName"), - new ComponentWithNamedCascadingParam()); - - // Act - var result = CascadingParameterState.FindCascadingParameters(states.Last()); - - // Assert - Assert.Null(result); - } - - [Fact] - public void FindCascadingParameters_MatchingNameButMismatchingType_ReturnsNull() - { - // Arrange - var states = CreateAncestry( - CreateCascadingValueComponent(new ValueType2(), "MatchOnName"), - new ComponentWithNamedCascadingParam()); - - // Act - var result = CascadingParameterState.FindCascadingParameters(states.Last()); - - // Assert - Assert.Null(result); - } - - [Fact] - public void FindCascadingParameters_MatchingNameAndType_ReturnsMatches() - { - // Arrange - var states = CreateAncestry( - CreateCascadingValueComponent(new ValueType1(), "matchonNAME"), // To show it's case-insensitive - new ComponentWithNamedCascadingParam()); - - // Act - var result = CascadingParameterState.FindCascadingParameters(states.Last()); - - // Assert - Assert.Collection(result, match => { - Assert.Equal(nameof(ComponentWithNamedCascadingParam.SomeLocalName), match.LocalValueName); - Assert.Same(states[0].Component, match.ValueSupplier); - }); - } - - [Fact] - public void FindCascadingParameters_MultipleMatchingAncestors_ReturnsClosestMatches() - { - // Arrange - var states = CreateAncestry( - CreateCascadingValueComponent(new ValueType1()), - CreateCascadingValueComponent(new ValueType2()), - CreateCascadingValueComponent(new ValueType1()), - CreateCascadingValueComponent(new ValueType2()), - new ComponentWithCascadingParams()); - - // Act - var result = CascadingParameterState.FindCascadingParameters(states.Last()); - - // Assert - Assert.Collection(result.OrderBy(x => x.LocalValueName), - match => { - Assert.Equal(nameof(ComponentWithCascadingParams.CascadingParam1), match.LocalValueName); - Assert.Same(states[2].Component, match.ValueSupplier); - }, - match => { - Assert.Equal(nameof(ComponentWithCascadingParams.CascadingParam2), match.LocalValueName); - Assert.Same(states[3].Component, match.ValueSupplier); - }); - } - - [Fact] - public void FindCascadingParameters_CanOverrideNonNullValueWithNull() - { - // Arrange - var states = CreateAncestry( - CreateCascadingValueComponent(new ValueType1()), - CreateCascadingValueComponent((ValueType1)null), - new ComponentWithCascadingParams()); - - // Act - var result = CascadingParameterState.FindCascadingParameters(states.Last()); - - // Assert - Assert.Collection(result.OrderBy(x => x.LocalValueName), - match => { - Assert.Equal(nameof(ComponentWithCascadingParams.CascadingParam1), match.LocalValueName); - Assert.Same(states[1].Component, match.ValueSupplier); - Assert.Null(match.ValueSupplier.CurrentValue); - }); - } - - static ComponentState[] CreateAncestry(params IComponent[] components) - { - var result = new ComponentState[components.Length]; - - for (var i = 0; i < components.Length; i++) - { - result[i] = CreateComponentState( - components[i], - i == 0 ? null : result[i - 1]); - } - - return result; - } - - static ComponentState CreateComponentState( - IComponent component, ComponentState parentComponentState = null) - { - return new ComponentState(new TestRenderer(), 0, component, parentComponentState); - } - - static CascadingValue CreateCascadingValueComponent(T value, string name = null) - { - var supplier = new CascadingValue(); - var renderer = new TestRenderer(); - supplier.Attach(new RenderHandle(renderer, 0)); - - var supplierParams = new Dictionary - { - { "Value", value } - }; - - if (name != null) - { - supplierParams.Add("Name", name); - } - - renderer.Dispatcher.InvokeAsync((Action)(() => supplier.SetParametersAsync(ParameterView.FromDictionary(supplierParams)))); - return supplier; - } - - class ComponentWithNoParams : TestComponentBase - { - } - - class ComponentWithNoCascadingParams : TestComponentBase - { - [Parameter] public bool SomeRegularParameter { get; set; } - } - - class ComponentWithCascadingParams : TestComponentBase - { - [Parameter] public bool RegularParam { get; set; } - [CascadingParameter] internal ValueType1 CascadingParam1 { get; set; } - [CascadingParameter] internal ValueType2 CascadingParam2 { get; set; } - } - - class ComponentWithInheritedCascadingParams : ComponentWithCascadingParams - { - [CascadingParameter] internal ValueType3 CascadingParam3 { get; set; } - } - - class ComponentWithGenericCascadingParam : TestComponentBase - { - [CascadingParameter] internal T LocalName { get; set; } - } - - class ComponentWithNamedCascadingParam : TestComponentBase - { - [CascadingParameter(Name = "MatchOnName")] - internal ValueType1 SomeLocalName { get; set; } - } - - class TestComponentBase : IComponent - { - public void Attach(RenderHandle renderHandle) - => throw new NotImplementedException(); - - public Task SetParametersAsync(ParameterView parameters) - => throw new NotImplementedException(); - } - - class ValueType1 { } - class ValueType2 { } - class ValueType3 { } - - class CascadingValueTypeBaseClass { } - class CascadingValueTypeDerivedClass : CascadingValueTypeBaseClass, ICascadingValueTypeDerivedClassInterface { } - interface ICascadingValueTypeDerivedClassInterface { } - } -} diff --git a/src/Components/Components/test/CascadingParameterTest.cs b/src/Components/Components/test/CascadingParameterTest.cs deleted file mode 100644 index a906664741..0000000000 --- a/src/Components/Components/test/CascadingParameterTest.cs +++ /dev/null @@ -1,449 +0,0 @@ -// 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.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Components.Rendering; -using Microsoft.AspNetCore.Components.RenderTree; -using Microsoft.AspNetCore.Components.Test.Helpers; -using Xunit; - -namespace Microsoft.AspNetCore.Components.Test -{ - public class CascadingParameterTest - { - [Fact] - public void PassesCascadingParametersToNestedComponents() - { - // Arrange - var renderer = new TestRenderer(); - var component = new TestComponent(builder => - { - builder.OpenComponent>(0); - builder.AddAttribute(1, "Value", "Hello"); - builder.AddAttribute(2, "ChildContent", new RenderFragment(childBuilder => - { - childBuilder.OpenComponent>(0); - childBuilder.AddAttribute(1, "RegularParameter", "Goodbye"); - childBuilder.CloseComponent(); - })); - builder.CloseComponent(); - }); - - // Act/Assert - var componentId = renderer.AssignRootComponentId(component); - component.TriggerRender(); - var batch = renderer.Batches.Single(); - var nestedComponent = FindComponent>(batch, out var nestedComponentId); - var nestedComponentDiff = batch.DiffsByComponentId[nestedComponentId].Single(); - - // The nested component was rendered with the correct parameters - Assert.Collection(nestedComponentDiff.Edits, - edit => - { - Assert.Equal(RenderTreeEditType.PrependFrame, edit.Type); - AssertFrame.Text( - batch.ReferenceFrames[edit.ReferenceFrameIndex], - "CascadingParameter=Hello; RegularParameter=Goodbye"); - }); - Assert.Equal(1, nestedComponent.NumRenders); - } - - [Fact] - public void RetainsCascadingParametersWhenUpdatingDirectParameters() - { - // Arrange - var renderer = new TestRenderer(); - var regularParameterValue = "Initial value"; - var component = new TestComponent(builder => - { - builder.OpenComponent>(0); - builder.AddAttribute(1, "Value", "Hello"); - builder.AddAttribute(2, "ChildContent", new RenderFragment(childBuilder => - { - childBuilder.OpenComponent>(0); - childBuilder.AddAttribute(1, "RegularParameter", regularParameterValue); - childBuilder.CloseComponent(); - })); - builder.CloseComponent(); - }); - - // Act 1: Render in initial state - var componentId = renderer.AssignRootComponentId(component); - component.TriggerRender(); - - // Capture the nested component so we can verify the update later - var firstBatch = renderer.Batches.Single(); - var nestedComponent = FindComponent>(firstBatch, out var nestedComponentId); - Assert.Equal(1, nestedComponent.NumRenders); - - // Act 2: Render again with updated regular parameter - regularParameterValue = "Changed value"; - component.TriggerRender(); - - // Assert - Assert.Equal(2, renderer.Batches.Count); - var secondBatch = renderer.Batches[1]; - var nestedComponentDiff = secondBatch.DiffsByComponentId[nestedComponentId].Single(); - - // The nested component was rendered with the correct parameters - Assert.Collection(nestedComponentDiff.Edits, - edit => - { - Assert.Equal(RenderTreeEditType.UpdateText, edit.Type); - Assert.Equal(0, edit.ReferenceFrameIndex); // This is the only change - AssertFrame.Text(secondBatch.ReferenceFrames[0], "CascadingParameter=Hello; RegularParameter=Changed value"); - }); - Assert.Equal(2, nestedComponent.NumRenders); - } - - [Fact] - public void NotifiesDescendantsOfUpdatedCascadingParameterValuesAndPreservesDirectParameters() - { - // Arrange - var providedValue = "Initial value"; - var renderer = new TestRenderer(); - var component = new TestComponent(builder => - { - builder.OpenComponent>(0); - builder.AddAttribute(1, "Value", providedValue); - builder.AddAttribute(2, "ChildContent", new RenderFragment(childBuilder => - { - childBuilder.OpenComponent>(0); - childBuilder.AddAttribute(1, "RegularParameter", "Goodbye"); - childBuilder.CloseComponent(); - })); - builder.CloseComponent(); - }); - - // Act 1: Initial render; capture nested component ID - var componentId = renderer.AssignRootComponentId(component); - component.TriggerRender(); - var firstBatch = renderer.Batches.Single(); - var nestedComponent = FindComponent>(firstBatch, out var nestedComponentId); - Assert.Equal(1, nestedComponent.NumRenders); - - // Act 2: Re-render CascadingValue with new value - providedValue = "Updated value"; - component.TriggerRender(); - - // Assert: We re-rendered CascadingParameterConsumerComponent - Assert.Equal(2, renderer.Batches.Count); - var secondBatch = renderer.Batches[1]; - var nestedComponentDiff = secondBatch.DiffsByComponentId[nestedComponentId].Single(); - - // The nested component was rendered with the correct parameters - Assert.Collection(nestedComponentDiff.Edits, - edit => - { - Assert.Equal(RenderTreeEditType.UpdateText, edit.Type); - Assert.Equal(0, edit.ReferenceFrameIndex); // This is the only change - AssertFrame.Text(secondBatch.ReferenceFrames[0], "CascadingParameter=Updated value; RegularParameter=Goodbye"); - }); - Assert.Equal(2, nestedComponent.NumRenders); - } - - [Fact] - public void DoesNotNotifyDescendantsIfCascadingParameterValuesAreImmutableAndUnchanged() - { - // Arrange - var renderer = new TestRenderer(); - var component = new TestComponent(builder => - { - builder.OpenComponent>(0); - builder.AddAttribute(1, "Value", "Unchanging value"); - builder.AddAttribute(2, "ChildContent", new RenderFragment(childBuilder => - { - childBuilder.OpenComponent>(0); - childBuilder.AddAttribute(1, "RegularParameter", "Goodbye"); - childBuilder.CloseComponent(); - })); - builder.CloseComponent(); - }); - - // Act 1: Initial render - var componentId = renderer.AssignRootComponentId(component); - component.TriggerRender(); - var firstBatch = renderer.Batches.Single(); - var nestedComponent = FindComponent>(firstBatch, out _); - Assert.Equal(3, firstBatch.DiffsByComponentId.Count); // Root + CascadingValue + nested - Assert.Equal(1, nestedComponent.NumRenders); - - // Act/Assert: Re-render the CascadingValue; observe nested component wasn't re-rendered - component.TriggerRender(); - - // Assert: We did not re-render CascadingParameterConsumerComponent - Assert.Equal(2, renderer.Batches.Count); - var secondBatch = renderer.Batches[1]; - Assert.Equal(2, secondBatch.DiffsByComponentId.Count); // Root + CascadingValue, but not nested one - Assert.Equal(1, nestedComponent.NumRenders); - } - - [Fact] - public void StopsNotifyingDescendantsIfTheyAreRemoved() - { - // Arrange - var providedValue = "Initial value"; - var displayNestedComponent = true; - var renderer = new TestRenderer(); - var component = new TestComponent(builder => - { - // At the outer level, have an unrelated fixed cascading value to show we can deal with combining both types - builder.OpenComponent>(0); - builder.AddAttribute(1, "Value", 123); - builder.AddAttribute(2, "IsFixed", true); - builder.AddAttribute(3, "ChildContent", new RenderFragment(builder2 => - { - // Then also have a non-fixed cascading value so we can show that unsubscription works - builder2.OpenComponent>(0); - builder2.AddAttribute(1, "Value", providedValue); - builder2.AddAttribute(2, "ChildContent", new RenderFragment(builder3 => - { - if (displayNestedComponent) - { - builder3.OpenComponent>(0); - builder3.AddAttribute(1, "RegularParameter", "Goodbye"); - builder3.CloseComponent(); - } - })); - builder2.CloseComponent(); - })); - builder.CloseComponent(); - }); - - // Act 1: Initial render; capture nested component ID - var componentId = renderer.AssignRootComponentId(component); - component.TriggerRender(); - var firstBatch = renderer.Batches.Single(); - var nestedComponent = FindComponent>(firstBatch, out var nestedComponentId); - Assert.Equal(1, nestedComponent.NumSetParametersCalls); - Assert.Equal(1, nestedComponent.NumRenders); - - // Act/Assert 2: Re-render the CascadingValue; observe nested component wasn't re-rendered - providedValue = "Updated value"; - displayNestedComponent = false; // Remove the nested componet - component.TriggerRender(); - - // Assert: We did not render the nested component now it's been removed - Assert.Equal(2, renderer.Batches.Count); - var secondBatch = renderer.Batches[1]; - Assert.Equal(1, nestedComponent.NumRenders); - Assert.Equal(3, secondBatch.DiffsByComponentId.Count); // Root + CascadingValue + CascadingValue, but not nested component - - // We *did* send updated params during the first render where it was removed, - // because the params are sent before the disposal logic runs. We could avoid - // this by moving the notifications into the OnAfterRender phase, but then we'd - // often render descendants twice (once because they are descendants and some - // direct parameter might have changed, then once because a cascading parameter - // changed). We can't have it both ways, so optimize for the case when the - // nested component *hasn't* just been removed. - Assert.Equal(2, nestedComponent.NumSetParametersCalls); - - // Act 3: However, after disposal, the subscription is removed, so we won't send - // updated params on subsequent CascadingValue renders. - providedValue = "Updated value 2"; - component.TriggerRender(); - Assert.Equal(2, nestedComponent.NumSetParametersCalls); - } - - [Fact] - public void DoesNotNotifyDescendantsOfUpdatedCascadingParameterValuesWhenFixed() - { - // Arrange - var providedValue = "Initial value"; - var shouldIncludeChild = true; - var renderer = new TestRenderer(); - var component = new TestComponent(builder => - { - builder.OpenComponent>(0); - builder.AddAttribute(1, "Value", providedValue); - builder.AddAttribute(2, "IsFixed", true); - builder.AddAttribute(3, "ChildContent", new RenderFragment(childBuilder => - { - if (shouldIncludeChild) - { - childBuilder.OpenComponent>(0); - childBuilder.AddAttribute(1, "RegularParameter", "Goodbye"); - childBuilder.CloseComponent(); - } - })); - builder.CloseComponent(); - }); - - // Act 1: Initial render; capture nested component ID - var componentId = renderer.AssignRootComponentId(component); - component.TriggerRender(); - var firstBatch = renderer.Batches.Single(); - var nestedComponent = FindComponent>(firstBatch, out var nestedComponentId); - Assert.Equal(1, nestedComponent.NumRenders); - - // Assert: Initial value is supplied to descendant - var nestedComponentDiff = firstBatch.DiffsByComponentId[nestedComponentId].Single(); - Assert.Collection(nestedComponentDiff.Edits, edit => - { - Assert.Equal(RenderTreeEditType.PrependFrame, edit.Type); - AssertFrame.Text( - firstBatch.ReferenceFrames[edit.ReferenceFrameIndex], - "CascadingParameter=Initial value; RegularParameter=Goodbye"); - }); - - // Act 2: Re-render CascadingValue with new value - providedValue = "Updated value"; - component.TriggerRender(); - - // Assert: We did not re-render the descendant - Assert.Equal(2, renderer.Batches.Count); - var secondBatch = renderer.Batches[1]; - Assert.Equal(2, secondBatch.DiffsByComponentId.Count); // Root + CascadingValue, but not nested one - Assert.Equal(1, nestedComponent.NumSetParametersCalls); - Assert.Equal(1, nestedComponent.NumRenders); - - // Act 3: Dispose - shouldIncludeChild = false; - component.TriggerRender(); - - // Assert: Absence of an exception here implies we didn't cause a problem by - // trying to remove a non-existent subscription - } - - [Fact] - public void CascadingValueThrowsIfFixedFlagChangesToTrue() - { - // Arrange - var renderer = new TestRenderer(); - var isFixed = false; - var component = new TestComponent(builder => - { - builder.OpenComponent>(0); - builder.AddAttribute(1, "IsFixed", isFixed); - builder.AddAttribute(2, "Value", new object()); - builder.CloseComponent(); - }); - renderer.AssignRootComponentId(component); - component.TriggerRender(); - - // Act/Assert - isFixed = true; - var ex = Assert.Throws(() => component.TriggerRender()); - Assert.Equal("The value of IsFixed cannot be changed dynamically.", ex.Message); - } - - [Fact] - public void CascadingValueThrowsIfFixedFlagChangesToFalse() - { - // Arrange - var renderer = new TestRenderer(); - var isFixed = true; - var component = new TestComponent(builder => - { - builder.OpenComponent>(0); - if (isFixed) // Showing also that "unset" is treated as "false" - { - builder.AddAttribute(1, "IsFixed", true); - } - builder.AddAttribute(2, "Value", new object()); - builder.CloseComponent(); - }); - renderer.AssignRootComponentId(component); - component.TriggerRender(); - - // Act/Assert - isFixed = false; - var ex = Assert.Throws(() => component.TriggerRender()); - Assert.Equal("The value of IsFixed cannot be changed dynamically.", ex.Message); - } - - [Fact] - public void ParameterViewSuppliedWithCascadingParametersCannotBeUsedAfterSynchronousReturn() - { - // Arrange - var providedValue = "Initial value"; - var renderer = new TestRenderer(); - var component = new TestComponent(builder => - { - builder.OpenComponent>(0); - builder.AddAttribute(1, "Value", providedValue); - builder.AddAttribute(2, "ChildContent", new RenderFragment(childBuilder => - { - childBuilder.OpenComponent>(0); - childBuilder.CloseComponent(); - })); - builder.CloseComponent(); - }); - - // Initial render; capture nested component - var componentId = renderer.AssignRootComponentId(component); - component.TriggerRender(); - var firstBatch = renderer.Batches.Single(); - var nestedComponent = FindComponent>(firstBatch, out var nestedComponentId); - - // Re-render CascadingValue with new value, so it gets a new ParameterView - providedValue = "Updated value"; - component.TriggerRender(); - Assert.Equal(2, renderer.Batches.Count); - - // It's no longer able to access anything in the ParameterView it just received - var ex = Assert.Throws(nestedComponent.AttemptIllegalAccessToLastParameterView); - Assert.Equal($"The {nameof(ParameterView)} instance can no longer be read because it has expired. {nameof(ParameterView)} can only be read synchronously and must not be stored for later use.", ex.Message); - } - - private static T FindComponent(CapturedBatch batch, out int componentId) - { - var componentFrame = batch.ReferenceFrames.Single( - frame => frame.FrameType == RenderTreeFrameType.Component - && frame.Component is T); - componentId = componentFrame.ComponentId; - return (T)componentFrame.Component; - } - - class TestComponent : AutoRenderComponent - { - private readonly RenderFragment _renderFragment; - - public TestComponent(RenderFragment renderFragment) - { - _renderFragment = renderFragment; - } - - protected override void BuildRenderTree(RenderTreeBuilder builder) - => _renderFragment(builder); - } - - class CascadingParameterConsumerComponent : AutoRenderComponent - { - private ParameterView lastParameterView; - - public int NumSetParametersCalls { get; private set; } - public int NumRenders { get; private set; } - - [CascadingParameter] T CascadingParameter { get; set; } - [Parameter] public string RegularParameter { get; set; } - - public override async Task SetParametersAsync(ParameterView parameters) - { - lastParameterView = parameters; - NumSetParametersCalls++; - await base.SetParametersAsync(parameters); - } - - protected override void BuildRenderTree(RenderTreeBuilder builder) - { - NumRenders++; - builder.AddContent(0, $"CascadingParameter={CascadingParameter}; RegularParameter={RegularParameter}"); - } - - public void AttemptIllegalAccessToLastParameterView() - { - // You're not allowed to hold onto a ParameterView and access it later, - // so this should throw - lastParameterView.TryGetValue("anything", out _); - } - } - - class SecondCascadingParameterConsumerComponent : CascadingParameterConsumerComponent - { - [CascadingParameter] T2 SecondCascadingParameter { get; set; } - } - } -} diff --git a/src/Components/Components/test/ComponentBaseTest.cs b/src/Components/Components/test/ComponentBaseTest.cs deleted file mode 100644 index bd09cc49c5..0000000000 --- a/src/Components/Components/test/ComponentBaseTest.cs +++ /dev/null @@ -1,581 +0,0 @@ -// 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.Diagnostics; -using System.Reflection.Metadata.Ecma335; -using System.Runtime.ExceptionServices; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Components.Rendering; -using Microsoft.AspNetCore.Components.RenderTree; -using Microsoft.AspNetCore.Components.Test.Helpers; -using Xunit; - -namespace Microsoft.AspNetCore.Components.Test -{ - public class ComponentBaseTest - { - // Nothing should exceed the timeout in a successful run of the the tests, this is just here to catch - // failures. - private static readonly TimeSpan Timeout = Debugger.IsAttached ? System.Threading.Timeout.InfiniteTimeSpan : TimeSpan.FromSeconds(10); - - [Fact] - public void RunsOnInitWhenRendered() - { - // Arrange - var renderer = new TestRenderer(); - var component = new TestComponent(); - - var onInitRuns = 0; - component.OnInitLogic = c => onInitRuns++; - - // Act - var componentId = renderer.AssignRootComponentId(component); - renderer.RenderRootComponent(componentId); - - // Assert - Assert.Equal(1, onInitRuns); - } - - [Fact] - public void RunsOnInitAsyncWhenRendered() - { - // Arrange - var renderer = new TestRenderer(); - var component = new TestComponent(); - - var onInitAsyncRuns = 0; - component.RunsBaseOnInitAsync = false; - component.OnInitAsyncLogic = c => - { - onInitAsyncRuns++; - return Task.CompletedTask; - }; - - // Act - var componentId = renderer.AssignRootComponentId(component); - renderer.RenderRootComponent(componentId); - - // Assert - Assert.Equal(1, onInitAsyncRuns); - Assert.Single(renderer.Batches); - } - - [Fact] - public void RunsOnInitAsyncAlsoOnBaseClassWhenRendered() - { - // Arrange - var renderer = new TestRenderer(); - var component = new TestComponent(); - - var onInitAsyncRuns = 0; - component.RunsBaseOnInitAsync = true; - component.OnInitAsyncLogic = c => - { - onInitAsyncRuns++; - return Task.CompletedTask; - }; - - // Act - var componentId = renderer.AssignRootComponentId(component); - renderer.RenderRootComponent(componentId); - - // Assert - Assert.Equal(1, onInitAsyncRuns); - Assert.Single(renderer.Batches); - } - - [Fact] - public void RunsOnParametersSetWhenRendered() - { - // Arrange - var renderer = new TestRenderer(); - var component = new TestComponent(); - - var onParametersSetRuns = 0; - component.OnParametersSetLogic = c => onParametersSetRuns++; - - // Act - var componentId = renderer.AssignRootComponentId(component); - renderer.RenderRootComponent(componentId); - - // Assert - Assert.Equal(1, onParametersSetRuns); - Assert.Single(renderer.Batches); - } - - [Fact] - public void RunsOnParametersSetAsyncWhenRendered() - { - // Arrange - var renderer = new TestRenderer(); - var component = new TestComponent(); - - var onParametersSetAsyncRuns = 0; - component.RunsBaseOnParametersSetAsync = false; - component.OnParametersSetAsyncLogic = c => - { - onParametersSetAsyncRuns++; - return Task.CompletedTask; - }; - - // Act - var componentId = renderer.AssignRootComponentId(component); - renderer.RenderRootComponent(componentId); - - // Assert - Assert.Equal(1, onParametersSetAsyncRuns); - Assert.Single(renderer.Batches); - } - - [Fact] - public void RunsOnParametersSetAsyncAlsoOnBaseClassWhenRendered() - { - // Arrange - var renderer = new TestRenderer(); - var component = new TestComponent(); - - var onParametersSetAsyncRuns = 0; - component.RunsBaseOnParametersSetAsync = true; - component.OnParametersSetAsyncLogic = c => - { - onParametersSetAsyncRuns++; - return Task.CompletedTask; - }; - - // Act - var componentId = renderer.AssignRootComponentId(component); - renderer.RenderRootComponent(componentId); - - // Assert - Assert.Equal(1, onParametersSetAsyncRuns); - Assert.Single(renderer.Batches); - } - - [Fact] - public async Task RendersAfterParametersSetAsyncTaskIsCompleted() - { - // Arrange - var renderer = new TestRenderer(); - var component = new TestComponent(); - - component.Counter = 1; - var parametersSetTask = new TaskCompletionSource(); - component.RunsBaseOnParametersSetAsync = false; - component.OnParametersSetAsyncLogic = c => parametersSetTask.Task; - - // Act - var componentId = renderer.AssignRootComponentId(component); - var renderTask = renderer.RenderRootComponentAsync(componentId); - - // Assert - Assert.Single(renderer.Batches); - - // Completes task started by OnParametersSetAsync - component.Counter = 2; - parametersSetTask.SetResult(true); - - await renderTask; - - // Component should be rendered again - Assert.Equal(2, renderer.Batches.Count); - } - - [Fact] - public async Task RendersAfterParametersSetAndInitAsyncTasksAreCompleted() - { - // Arrange - var @event = new ManualResetEventSlim(); - - var renderer = new TestRenderer() - { - OnUpdateDisplayComplete = () => { @event.Set(); }, - }; - var component = new TestComponent(); - - component.Counter = 1; - var initTask = new TaskCompletionSource(); - var parametersSetTask = new TaskCompletionSource(); - component.RunsBaseOnInitAsync = true; - component.RunsBaseOnParametersSetAsync = true; - component.OnInitAsyncLogic = c => initTask.Task; - component.OnParametersSetAsyncLogic = c => parametersSetTask.Task; - - // Act - var componentId = renderer.AssignRootComponentId(component); - var renderTask = renderer.RenderRootComponentAsync(componentId); - - // Assert - // A rendering should have happened after the synchronous execution of Init - Assert.Single(renderer.Batches); - - @event.Reset(); - - // Completes task started by OnInitAsync - component.Counter = 2; - initTask.SetResult(true); - - // We need to wait here, because the continuation from SetResult needs to be scheduled. - @event.Wait(Timeout); - @event.Reset(); - - // Component should be rendered once, after set parameters - Assert.Equal(2, renderer.Batches.Count); - - // Completes task started by OnParametersSetAsync - component.Counter = 3; - parametersSetTask.SetResult(false); - - await renderTask; - Assert.True(@event.IsSet); - - // Component should be rendered again - // after the async part of onparameterssetasync completes - Assert.Equal(3, renderer.Batches.Count); - } - - [Fact] - public async Task DoesNotRenderAfterOnInitAsyncTaskIsCancelled() - { - // Arrange - var renderer = new TestRenderer(); - var component = new TestComponent() { Counter = 1 }; - var initTask = new TaskCompletionSource(); - component.OnInitAsyncLogic = _ => initTask.Task; - - // Act - var componentId = renderer.AssignRootComponentId(component); - var renderTask = renderer.RenderRootComponentAsync(componentId); - - // Assert - Assert.False(renderTask.IsCompleted); - Assert.Single(renderer.Batches); - - // Cancel task started by OnInitAsync - component.Counter = 2; - initTask.SetCanceled(); - - await renderTask; - - // Component should only be rendered again due to - // the call to StateHasChanged after SetParametersAsync - Assert.Equal(2, renderer.Batches.Count); - } - - [Fact] - public async Task RunsOnAfterRender_AfterRenderingCompletes() - { - // Arrange - var renderer = new TestRenderer(); - var component = new TestComponent() { Counter = 1 }; - - var onAfterRenderCompleted = false; - component.OnAfterRenderLogic = (c, firstRender) => - { - Assert.True(firstRender); - Assert.Single(renderer.Batches); - onAfterRenderCompleted = true; - }; - - // Act - var componentId = renderer.AssignRootComponentId(component); - var renderTask = renderer.RenderRootComponentAsync(componentId); - - // Assert - await renderTask; - Assert.True(onAfterRenderCompleted); - - // Component should not be rendered again. OnAfterRender doesn't do that. - Assert.Single(renderer.Batches); - - // Act: Render again! - onAfterRenderCompleted = false; - component.OnAfterRenderLogic = (c, firstRender) => - { - Assert.False(firstRender); - Assert.Equal(2, renderer.Batches.Count); - onAfterRenderCompleted = true; - }; - - renderTask = renderer.RenderRootComponentAsync(componentId); - - // Assert - Assert.True(onAfterRenderCompleted); - Assert.Equal(2, renderer.Batches.Count); - await renderTask; - } - - [Fact] - public async Task RunsOnAfterRenderAsync_AfterRenderingCompletes() - { - // Arrange - var renderer = new TestRenderer(); - var component = new TestComponent() { Counter = 1 }; - - var onAfterRenderCompleted = false; - var tcs = new TaskCompletionSource(); - component.OnAfterRenderAsyncLogic = async (c, firstRender) => - { - Assert.True(firstRender); - Assert.Single(renderer.Batches); - onAfterRenderCompleted = true; - await tcs.Task; - }; - - // Act - var componentId = renderer.AssignRootComponentId(component); - var renderTask = renderer.RenderRootComponentAsync(componentId); - - // Assert - tcs.SetResult(null); - await renderTask; - Assert.True(onAfterRenderCompleted); - - // Component should not be rendered again. OnAfterRenderAsync doesn't do that. - Assert.Single(renderer.Batches); - - // Act: Render again! - onAfterRenderCompleted = false; - tcs = new TaskCompletionSource(); - component.OnAfterRenderAsyncLogic = async (c, firstRender) => - { - Assert.False(firstRender); - Assert.Equal(2, renderer.Batches.Count); - onAfterRenderCompleted = true; - await tcs.Task; - }; - - renderTask = renderer.RenderRootComponentAsync(componentId); - - // Assert - tcs.SetResult(null); - await renderTask; - Assert.True(onAfterRenderCompleted); - Assert.Equal(2, renderer.Batches.Count); - } - - [Fact] - public async Task DoesNotRenderAfterOnInitAsyncTaskIsCancelledUsingCancellationToken() - { - // Arrange - var renderer = new TestRenderer(); - var component = new TestComponent() { Counter = 1 }; - - var cts = new CancellationTokenSource(); - cts.Cancel(); - component.OnInitAsyncLogic = async _ => - { - await Task.Yield(); - cts.Token.ThrowIfCancellationRequested(); - }; - - // Act - var componentId = renderer.AssignRootComponentId(component); - await renderer.RenderRootComponentAsync(componentId); - - // Assert - // At least one call to StateHasChanged depending on how OnInitAsyncLogic gets scheduled. - Assert.NotEmpty(renderer.Batches); - } - - [Fact] - public async Task DoesNotRenderAfterOnParametersSetAsyncTaskIsCanceled() - { - // Arrange - var renderer = new TestRenderer(); - var component = new TestComponent() { Counter = 1 }; - var onParametersSetTask = new TaskCompletionSource(); - component.OnParametersSetAsyncLogic = _ => onParametersSetTask.Task; - - // Act - var componentId = renderer.AssignRootComponentId(component); - var renderTask = renderer.RenderRootComponentAsync(componentId); - - // Assert - Assert.Single(renderer.Batches); - - // Cancel task started by OnParametersSet - component.Counter = 2; - onParametersSetTask.SetCanceled(); - - await renderTask; - - // Component should not be rendered again - Assert.Single(renderer.Batches); - - } - - [Fact] - public async Task RenderRootComponentAsync_ReportsErrorDuringOnInit() - { - // Arrange - var expected = new TimeZoneNotFoundException(); - var renderer = new TestRenderer(); - var component = new TestComponent { OnInitLogic = _ => throw expected }; - - // Act & Assert - var componentId = renderer.AssignRootComponentId(component); - var actual = await Assert.ThrowsAsync(() => renderer.RenderRootComponentAsync(componentId)); - - // Assert - Assert.Same(expected, actual); - } - - [Fact] - public async Task RenderRootComponentAsync_ReportsErrorDuringOnInitAsync() - { - // Arrange - var expected = new TimeZoneNotFoundException(); - var renderer = new TestRenderer(); - var component = new TestComponent { OnInitAsyncLogic = _ => Task.FromException(expected) }; - - // Act & Assert - var componentId = renderer.AssignRootComponentId(component); - var actual = await Assert.ThrowsAsync(() => renderer.RenderRootComponentAsync(componentId)); - - // Assert - Assert.Same(expected, actual); - } - - [Fact] - public async Task RenderRootComponentAsync_ReportsErrorDuringOnParameterSet() - { - // Arrange - var expected = new TimeZoneNotFoundException(); - var renderer = new TestRenderer(); - var component = new TestComponent { OnParametersSetLogic = _ => throw expected }; - - // Act & Assert - var componentId = renderer.AssignRootComponentId(component); - var actual = await Assert.ThrowsAsync(() => renderer.RenderRootComponentAsync(componentId)); - - // Assert - Assert.Same(expected, actual); - } - - [Fact] - public async Task RenderRootComponentAsync_ReportsErrorDuringOnParameterSetAsync() - { - // Arrange - var expected = new TimeZoneNotFoundException(); - var renderer = new TestRenderer(); - var component = new TestComponent { OnParametersSetAsyncLogic = _ => Task.FromException(expected) }; - - // Act & Assert - var componentId = renderer.AssignRootComponentId(component); - var actual = await Assert.ThrowsAsync(() => renderer.RenderRootComponentAsync(componentId)); - - // Assert - Assert.Same(expected, actual); - } - - private class TestComponent : ComponentBase - { - public bool RunsBaseOnInit { get; set; } = true; - - public bool RunsBaseOnInitAsync { get; set; } = true; - - public bool RunsBaseOnParametersSet { get; set; } = true; - - public bool RunsBaseOnParametersSetAsync { get; set; } = true; - - public bool RunsBaseOnAfterRender { get; set; } = true; - - public bool RunsBaseOnAfterRenderAsync { get; set; } = true; - - public Action OnInitLogic { get; set; } - - public Func OnInitAsyncLogic { get; set; } - - public Action OnParametersSetLogic { get; set; } - - public Func OnParametersSetAsyncLogic { get; set; } - - public Action OnAfterRenderLogic { get; set; } - - public Func OnAfterRenderAsyncLogic { get; set; } - - public int Counter { get; set; } - - protected override void BuildRenderTree(RenderTreeBuilder builder) - { - builder.OpenElement(0, "p"); - builder.AddContent(1, Counter); - builder.CloseElement(); - } - - protected override void OnInitialized() - { - if (RunsBaseOnInit) - { - base.OnInitialized(); - } - - OnInitLogic?.Invoke(this); - } - - protected override async Task OnInitializedAsync() - { - if (RunsBaseOnInitAsync) - { - await base.OnInitializedAsync(); - } - - if (OnInitAsyncLogic != null) - { - await OnInitAsyncLogic.Invoke(this); - } - } - - protected override void OnParametersSet() - { - if (RunsBaseOnParametersSet) - { - base.OnParametersSet(); - } - - OnParametersSetLogic?.Invoke(this); - } - - protected override async Task OnParametersSetAsync() - { - if (RunsBaseOnParametersSetAsync) - { - await base.OnParametersSetAsync(); - } - - if (OnParametersSetAsyncLogic != null) - { - await OnParametersSetAsyncLogic(this); - } - } - - protected override void OnAfterRender(bool firstRender) - { - if (RunsBaseOnAfterRender) - { - base.OnAfterRender(firstRender); - } - - if (OnAfterRenderLogic != null) - { - OnAfterRenderLogic(this, firstRender); - } - } - - protected override async Task OnAfterRenderAsync(bool firstRender) - { - if (RunsBaseOnAfterRenderAsync) - { - await base.OnAfterRenderAsync(firstRender); - } - - if (OnAfterRenderAsyncLogic != null) - { - await OnAfterRenderAsyncLogic(this, firstRender); - } - } - } - } -} diff --git a/src/Components/Components/test/ComponentFactoryTest.cs b/src/Components/Components/test/ComponentFactoryTest.cs deleted file mode 100644 index 4dd4de56e0..0000000000 --- a/src/Components/Components/test/ComponentFactoryTest.cs +++ /dev/null @@ -1,168 +0,0 @@ -// 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.Collections.Generic; -using System.Text; -using System.Threading.Tasks; -using Microsoft.Extensions.DependencyInjection; -using Xunit; - -namespace Microsoft.AspNetCore.Components -{ - public class ComponentFactoryTest - { - [Fact] - public void InstantiateComponent_CreatesInstance() - { - // Arrange - var componentType = typeof(EmptyComponent); - var factory = new ComponentFactory(); - - // Act - var instance = factory.InstantiateComponent(GetServiceProvider(), componentType); - - // Assert - Assert.NotNull(instance); - Assert.IsType(instance); - } - - [Fact] - public void InstantiateComponent_AssignsPropertiesWithInjectAttribute() - { - // Arrange - var componentType = typeof(ComponentWithInjectProperties); - var factory = new ComponentFactory(); - - // Act - var instance = factory.InstantiateComponent(GetServiceProvider(), componentType); - - // Assert - Assert.NotNull(instance); - var component = Assert.IsType(instance); - // Public, and non-public properties, and properties with non-public setters should get assigned - Assert.NotNull(component.Property1); - Assert.NotNull(component.GetProperty2()); - Assert.NotNull(component.Property3); - Assert.NotNull(component.Property4); - } - - [Fact] - public void InstantiateComponent_AssignsPropertiesWithInjectAttributeOnBaseType() - { - // Arrange - var componentType = typeof(DerivedComponent); - var factory = new ComponentFactory(); - - // Act - var instance = factory.InstantiateComponent(GetServiceProvider(), componentType); - - // Assert - Assert.NotNull(instance); - var component = Assert.IsType(instance); - Assert.NotNull(component.Property1); - Assert.NotNull(component.GetProperty2()); - Assert.NotNull(component.Property3); - - // Property on derived type without [Inject] should not be assigned - Assert.Null(component.Property4); - // Property on the base type with the [Inject] attribute should - Assert.NotNull(((ComponentWithInjectProperties)component).Property4); - } - - [Fact] - public void InstantiateComponent_IgnoresPropertiesWithoutInjectAttribute() - { - // Arrange - var componentType = typeof(ComponentWithNonInjectableProperties); - var factory = new ComponentFactory(); - - // Act - var instance = factory.InstantiateComponent(GetServiceProvider(), componentType); - - // Assert - Assert.NotNull(instance); - var component = Assert.IsType(instance); - // Public, and non-public properties, and properties with non-public setters should get assigned - Assert.NotNull(component.Property1); - Assert.Null(component.Property2); - } - - private static IServiceProvider GetServiceProvider() - { - return new ServiceCollection() - .AddTransient() - .AddTransient() - .BuildServiceProvider(); - } - - private class EmptyComponent : IComponent - { - public void Attach(RenderHandle renderHandle) - { - throw new NotImplementedException(); - } - - public Task SetParametersAsync(ParameterView parameters) - { - throw new NotImplementedException(); - } - } - - private class ComponentWithInjectProperties : IComponent - { - [Inject] - public TestService1 Property1 { get; set; } - - [Inject] - private TestService2 Property2 { get; set; } - - [Inject] - public TestService1 Property3 { get; private set; } - - [Inject] - public TestService1 Property4 { get; set; } - - public TestService2 GetProperty2() => Property2; - - public void Attach(RenderHandle renderHandle) - { - throw new NotImplementedException(); - } - - public Task SetParametersAsync(ParameterView parameters) - { - throw new NotImplementedException(); - } - } - - private class ComponentWithNonInjectableProperties : IComponent - { - [Inject] - public TestService1 Property1 { get; set; } - - public TestService1 Property2 { get; set; } - - public void Attach(RenderHandle renderHandle) - { - throw new NotImplementedException(); - } - - public Task SetParametersAsync(ParameterView parameters) - { - throw new NotImplementedException(); - } - } - - private class DerivedComponent : ComponentWithInjectProperties - { - public new TestService2 Property4 { get; set; } - - [Inject] - public TestService2 Property5 { get; set; } - } - - public class TestService1 { } - public class TestService2 { } - } -} diff --git a/src/Components/Components/test/DependencyInjectionTest.cs b/src/Components/Components/test/DependencyInjectionTest.cs deleted file mode 100644 index 2a77c75325..0000000000 --- a/src/Components/Components/test/DependencyInjectionTest.cs +++ /dev/null @@ -1,204 +0,0 @@ -// 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.AspNetCore.Components; -using Microsoft.AspNetCore.Components.Test.Helpers; -using System; -using System.Threading.Tasks; -using Xunit; - -namespace Microsoft.AspNetCore.Components.Test -{ - public class DependencyInjectionTest - { - private readonly TestRenderer _renderer; - private readonly TestServiceProvider _serviceProvider; - - public DependencyInjectionTest() - { - _serviceProvider = new TestServiceProvider(); - _renderer = new TestRenderer(_serviceProvider); - } - - [Fact] - public void IgnoresPropertiesWithoutInjectAttribute() - { - // Arrange/Act - var component = InstantiateComponent(); - - // Assert - Assert.Null(component.SomeProperty); - Assert.Null(component.PrivatePropertyValue); - } - - [Fact] - public void IgnoresStaticProperties() - { - // Arrange/Act - var component = InstantiateComponent(); - - // Assert - Assert.Null(HasStaticProperties.StaticPropertyWithInject); - Assert.Null(HasStaticProperties.StaticPropertyWithoutInject); - } - - [Fact] - public void ThrowsForInjectablePropertiesWithoutSetter() - { - var ex = Assert.Throws(() => - { - InstantiateComponent(); - }); - - Assert.Equal($"Cannot provide a value for property '{nameof(HasInjectableProperty.MyService)}' " + - $"on type '{typeof(HasGetOnlyPropertyWithInject).FullName}' because the property " + - $"has no setter.", ex.Message); - } - - [Fact] - public void ThrowsIfNoSuchServiceIsRegistered() - { - var ex = Assert.Throws(() => - { - InstantiateComponent(); - }); - - Assert.Equal($"Cannot provide a value for property '{nameof(HasInjectableProperty.MyService)}' " + - $"on type '{typeof(HasInjectableProperty).FullName}'. There is no registered service " + - $"of type '{typeof(IMyService).FullName}'.", ex.Message); - } - - [Fact] - public void SetsInjectablePropertyValueIfServiceIsRegistered() - { - // Arrange - var serviceInstance = new MyServiceImplementation(); - _serviceProvider.AddService(serviceInstance); - - // Act - var instance = InstantiateComponent(); - - // Assert - Assert.Same(serviceInstance, instance.MyService); - } - - [Fact] - public void HandlesInjectablePropertyScenarios() - { - // Arrange - var serviceInstance = new MyServiceImplementation(); - var otherServiceInstance = new MyOtherServiceImplementation(); - var concreteServiceInstance = new MyConcreteService(); - _serviceProvider.AddService(serviceInstance); - _serviceProvider.AddService(otherServiceInstance); - _serviceProvider.AddService(concreteServiceInstance); - - // Act - var instance = InstantiateComponent(); - - // Assert - Assert.Same(serviceInstance, instance.PublicReadWrite); - Assert.Same(serviceInstance, instance.PublicReadOnly); - Assert.Same(serviceInstance, instance.PrivateValue); - Assert.Same(otherServiceInstance, instance.DifferentServiceType); - Assert.Same(concreteServiceInstance, instance.ConcreteServiceType); - } - - [Fact] - public void SetsInheritedInjectableProperties() - { - // Arrange - var serviceInstance = new MyServiceImplementation(); - _serviceProvider.AddService(serviceInstance); - - // Act - var instance = InstantiateComponent(); - - // Assert - Assert.Same(serviceInstance, instance.MyService); - } - - [Fact] - public void SetsPrivateInheritedInjectableProperties() - { - // Arrange - var serviceInstance = new MyServiceImplementation(); - _serviceProvider.AddService(serviceInstance); - - // Act - var instance = InstantiateComponent(); - - // Assert - Assert.Same(serviceInstance, instance.PrivateMyService); - } - - private T InstantiateComponent() where T: IComponent - => _renderer.InstantiateComponent(); - - class HasPropertiesWithoutInjectAttribute : TestComponent - { - public IMyService SomeProperty { get; set; } - public IMyService PrivatePropertyValue => PrivateProperty; - private IMyService PrivateProperty { get; set; } - } - - class HasStaticProperties : TestComponent - { - [Inject] public static IMyService StaticPropertyWithInject { get; set; } - public static IMyService StaticPropertyWithoutInject { get; set; } - } - - class HasGetOnlyPropertyWithInject : TestComponent - { - [Inject] public IMyService MyService { get; } - } - - class HasInjectableProperty : TestComponent - { - [Inject] public IMyService MyService { get; set; } - } - - class HasPrivateInjectableProperty : TestComponent - { - [Inject] private IMyService MyService { get; set; } - - public IMyService PrivateMyService => MyService; - } - - class HasInheritedPrivateInjectableProperty : HasPrivateInjectableProperty { } - - class HasManyInjectableProperties : TestComponent - { - [Inject] public IMyService PublicReadWrite { get; set; } - [Inject] public IMyService PublicReadOnly { get; private set; } - [Inject] private IMyService Private { get; set; } - [Inject] public IMyOtherService DifferentServiceType { get; set; } - [Inject] public MyConcreteService ConcreteServiceType { get; set; } - - public IMyService PrivateValue => Private; - } - - class HasInheritedInjectedProperty : HasInjectableProperty { } - - interface IMyService { } - interface IMyOtherService { } - - class MyServiceImplementation : IMyService { } - class MyOtherServiceImplementation : IMyOtherService { } - class MyConcreteService { } - - class TestComponent : IComponent - { - // IMPORTANT: The fact that these throw demonstrates that the injection - // happens before any of the lifecycle methods. If you change these to - // not throw, then be sure also to add a test to verify that injection - // occurs before lifecycle methods. - - public void Attach(RenderHandle renderHandle) - => throw new NotImplementedException(); - - public Task SetParametersAsync(ParameterView parameters) - => throw new NotImplementedException(); - } - } -} diff --git a/src/Components/Components/test/EventCallbackFactoryBinderExtensionsTest.cs b/src/Components/Components/test/EventCallbackFactoryBinderExtensionsTest.cs deleted file mode 100644 index 8df5092112..0000000000 --- a/src/Components/Components/test/EventCallbackFactoryBinderExtensionsTest.cs +++ /dev/null @@ -1,713 +0,0 @@ -// 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.ComponentModel; -using System.Globalization; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Testing; -using Xunit; - -namespace Microsoft.AspNetCore.Components -{ - public class EventCallbackFactoryBinderExtensionsTest - { - [Fact] - public async Task CreateBinder_SwallowsConversionException() - { - // Arrange - var value = 17; - var component = new EventCountingComponent(); - Action setter = (_) => value = _; - - var binder = EventCallback.Factory.CreateBinder(component, setter, value); - - // Act - await binder.InvokeAsync(new ChangeEventArgs() { Value = "not-an-integer!", }); - - Assert.Equal(17, value); // Setter not called - Assert.Equal(1, component.Count); - } - - [Fact] - public async Task CreateBinder_IfConverterThrows_ConvertsEmptyStringToDefault() - { - // Arrange - var value = 17; - var component = new EventCountingComponent(); - Action setter = (_) => value = _; - - var binder = EventCallback.Factory.CreateBinder(component, setter, value); - - // Act - await binder.InvokeAsync(new ChangeEventArgs() { Value = string.Empty, }); - - Assert.Equal(0, value); // Calls setter to apply default value for this type - Assert.Equal(1, component.Count); - } - - [Fact] - public async Task CreateBinder_ThrowsSetterException() - { - // Arrange - var component = new EventCountingComponent(); - Action setter = (_) => { throw new InvalidTimeZoneException(); }; - - var binder = EventCallback.Factory.CreateBinder(component, setter, 17); - - // Act - await Assert.ThrowsAsync(() => - { - return binder.InvokeAsync(new ChangeEventArgs() { Value = "18", }); - }); - - Assert.Equal(1, component.Count); - } - - [Fact] - public async Task CreateBinder_BindsEmpty_DoesNotCallSetter() - { - // Arrange - var value = 17; - var component = new EventCountingComponent(); - Action setter = (_) => value = _; - - var binder = EventCallback.Factory.CreateBinder(component, setter, value); - - // Act - await binder.InvokeAsync(new ChangeEventArgs() { Value = "not-an-integer!", }); - - Assert.Equal(17, value); // Setter not called - Assert.Equal(1, component.Count); - } - - [Fact] - public async Task CreateBinder_BindsEmpty_CallsSetterForNullable() - { - // Arrange - var value = (int?)17; - var component = new EventCountingComponent(); - Action setter = (_) => value = _; - - var binder = EventCallback.Factory.CreateBinder(component, setter, value); - - // Act - await binder.InvokeAsync(new ChangeEventArgs() { Value = "", }); - - Assert.Null(value); // Setter called - Assert.Equal(1, component.Count); - } - - [Fact] - public async Task CreateBinder_String() - { - // Arrange - var value = "hi"; - var component = new EventCountingComponent(); - Action setter = (_) => value = _; - - var binder = EventCallback.Factory.CreateBinder(component, setter, value); - - var expectedValue = "bye"; - - // Act - await binder.InvokeAsync(new ChangeEventArgs() { Value = expectedValue, }); - - Assert.Equal(expectedValue, value); - Assert.Equal(1, component.Count); - } - - [Fact] - public async Task CreateBinder_Bool() - { - // Arrange - var value = false; - var component = new EventCountingComponent(); - Action setter = (_) => value = _; - - var binder = EventCallback.Factory.CreateBinder(component, setter, value); - - var expectedValue = true; - - // Act - await binder.InvokeAsync(new ChangeEventArgs() { Value = true, }); - - Assert.Equal(expectedValue, value); - Assert.Equal(1, component.Count); - } - - [Fact] - public async Task CreateBinder_NullableBool() - { - // Arrange - var value = (bool?)false; - var component = new EventCountingComponent(); - Action setter = (_) => value = _; - - var binder = EventCallback.Factory.CreateBinder(component, setter, value); - - var expectedValue = (bool?)true; - - // Act - await binder.InvokeAsync(new ChangeEventArgs() { Value = true, }); - - Assert.Equal(expectedValue, value); - Assert.Equal(1, component.Count); - } - - [Fact] - public async Task CreateBinder_Int() - { - // Arrange - var value = 17; - var component = new EventCountingComponent(); - Action setter = (_) => value = _; - - var binder = EventCallback.Factory.CreateBinder(component, setter, value); - - var expectedValue = 42; - - // Act - await binder.InvokeAsync(new ChangeEventArgs() { Value = "42", }); - - Assert.Equal(expectedValue, value); - Assert.Equal(1, component.Count); - } - - [Fact] - public async Task CreateBinder_NullableInt() - { - // Arrange - var value = (int?)17; - var component = new EventCountingComponent(); - Action setter = (_) => value = _; - - var binder = EventCallback.Factory.CreateBinder(component, setter, value); - - var expectedValue = (int?)42; - - // Act - await binder.InvokeAsync(new ChangeEventArgs() { Value = "42", }); - - Assert.Equal(expectedValue, value); - Assert.Equal(1, component.Count); - } - - [Fact] - public async Task CreateBinder_Long() - { - // Arrange - var value = (long)17; - var component = new EventCountingComponent(); - Action setter = (_) => value = _; - - var binder = EventCallback.Factory.CreateBinder(component, setter, value); - - var expectedValue = (long)42; - - // Act - await binder.InvokeAsync(new ChangeEventArgs() { Value = "42", }); - - Assert.Equal(expectedValue, value); - Assert.Equal(1, component.Count); - } - - [Fact] - public async Task CreateBinder_NullableLong() - { - // Arrange - var value = (long?)17; - var component = new EventCountingComponent(); - Action setter = (_) => value = _; - - var binder = EventCallback.Factory.CreateBinder(component, setter, value); - - var expectedValue = (long?)42; - - // Act - await binder.InvokeAsync(new ChangeEventArgs() { Value = "42", }); - - Assert.Equal(expectedValue, value); - Assert.Equal(1, component.Count); - } - - [Fact] - public async Task CreateBinder_Float() - { - // Arrange - var value = (float)17; - var component = new EventCountingComponent(); - Action setter = (_) => value = _; - - var binder = EventCallback.Factory.CreateBinder(component, setter, value); - - var expectedValue = (float)42; - - // Act - await binder.InvokeAsync(new ChangeEventArgs() { Value = "42", }); - - Assert.Equal(expectedValue, value); - Assert.Equal(1, component.Count); - } - - [Fact] - public async Task CreateBinder_NullableFloat() - { - // Arrange - var value = (float?)17; - var component = new EventCountingComponent(); - Action setter = (_) => value = _; - - var binder = EventCallback.Factory.CreateBinder(component, setter, value); - - var expectedValue = (float?)42; - - // Act - await binder.InvokeAsync(new ChangeEventArgs() { Value = "42", }); - - Assert.Equal(expectedValue, value); - Assert.Equal(1, component.Count); - } - - [Fact] - public async Task CreateBinder_Double() - { - // Arrange - var value = (double)17; - var component = new EventCountingComponent(); - Action setter = (_) => value = _; - - var binder = EventCallback.Factory.CreateBinder(component, setter, value); - - var expectedValue = (double)42; - - // Act - await binder.InvokeAsync(new ChangeEventArgs() { Value = "42", }); - - Assert.Equal(expectedValue, value); - Assert.Equal(1, component.Count); - } - - [Fact] - public async Task CreateBinder_NullableDouble() - { - // Arrange - var value = (double?)17; - var component = new EventCountingComponent(); - Action setter = (_) => value = _; - - var binder = EventCallback.Factory.CreateBinder(component, setter, value); - - var expectedValue = (double?)42; - - // Act - await binder.InvokeAsync(new ChangeEventArgs() { Value = "42", }); - - Assert.Equal(expectedValue, value); - Assert.Equal(1, component.Count); - } - - [Fact] - public async Task CreateBinder_Decimal() - { - // Arrange - var value = (decimal)17; - var component = new EventCountingComponent(); - Action setter = (_) => value = _; - - var binder = EventCallback.Factory.CreateBinder(component, setter, value); - - var expectedValue = (decimal)42; - - // Act - await binder.InvokeAsync(new ChangeEventArgs() { Value = "42", }); - - Assert.Equal(expectedValue, value); - Assert.Equal(1, component.Count); - } - - [Fact] - public async Task CreateBinder_NullableDecimal() - { - // Arrange - var value = (decimal?)17; - var component = new EventCountingComponent(); - Action setter = (_) => value = _; - - var binder = EventCallback.Factory.CreateBinder(component, setter, value); - - var expectedValue = (decimal?)42; - - // Act - await binder.InvokeAsync(new ChangeEventArgs() { Value = "42", }); - - Assert.Equal(expectedValue, value); - Assert.Equal(1, component.Count); - } - - [Fact] - public async Task CreateBinder_Enum() - { - // Arrange - var value = AttributeTargets.All; - var component = new EventCountingComponent(); - Action setter = (_) => value = _; - - var binder = EventCallback.Factory.CreateBinder(component, setter, value); - - var expectedValue = AttributeTargets.Class; - - // Act - await binder.InvokeAsync(new ChangeEventArgs() { Value = expectedValue.ToString(), }); - - Assert.Equal(expectedValue, value); - Assert.Equal(1, component.Count); - } - - [Fact] - public async Task CreateBinder_NullableEnum() - { - // Arrange - var value = (AttributeTargets?)AttributeTargets.All; - var component = new EventCountingComponent(); - Action setter = (_) => value = _; - - var binder = EventCallback.Factory.CreateBinder(component, setter, value); - - var expectedValue = AttributeTargets.Class; - - // Act - await binder.InvokeAsync(new ChangeEventArgs() { Value = expectedValue.ToString(), }); - - Assert.Equal(expectedValue, value); - Assert.Equal(1, component.Count); - } - - [Fact] - public async Task CreateBinder_DateTime() - { - // Arrange - var value = DateTime.Now; - var component = new EventCountingComponent(); - Action setter = (_) => value = _; - - var binder = EventCallback.Factory.CreateBinder(component, setter, value); - - var expectedValue = new DateTime(2018, 3, 4, 1, 2, 3); - - // Act - await binder.InvokeAsync(new ChangeEventArgs() { Value = expectedValue.ToString(), }); - - Assert.Equal(expectedValue, value); - Assert.Equal(1, component.Count); - } - - [Fact] - public async Task CreateBinder_NullableDateTime() - { - // Arrange - var value = (DateTime?)DateTime.Now; - var component = new EventCountingComponent(); - Action setter = (_) => value = _; - - var binder = EventCallback.Factory.CreateBinder(component, setter, value); - - var expectedValue = new DateTime(2018, 3, 4, 1, 2, 3); - - // Act - await binder.InvokeAsync(new ChangeEventArgs() { Value = expectedValue.ToString(), }); - - Assert.Equal(expectedValue, value); - Assert.Equal(1, component.Count); - } - - [Fact] - public async Task CreateBinder_DateTime_Format() - { - // Arrange - var value = DateTime.Now; - var component = new EventCountingComponent(); - Action setter = (_) => value = _; - var format = "ddd yyyy-MM-dd"; - - var binder = EventCallback.Factory.CreateBinder(component, setter, value, format); - - var expectedValue = new DateTime(2018, 3, 4); - - // Act - await binder.InvokeAsync(new ChangeEventArgs() { Value = expectedValue.ToString(format), }); - - Assert.Equal(expectedValue, value); - Assert.Equal(1, component.Count); - } - - [Fact] - public async Task CreateBinder_NullableDateTime_Format() - { - // Arrange - var value = (DateTime?)DateTime.Now; - var component = new EventCountingComponent(); - Action setter = (_) => value = _; - var format = "ddd yyyy-MM-dd"; - - var binder = EventCallback.Factory.CreateBinder(component, setter, value, format); - - var expectedValue = new DateTime(2018, 3, 4); - - // Act - await binder.InvokeAsync(new ChangeEventArgs() { Value = expectedValue.ToString(format), }); - - Assert.Equal(expectedValue, value); - Assert.Equal(1, component.Count); - } - - [Fact] - public async Task CreateBinder_DateTimeOffset() - { - // Arrange - var value = DateTimeOffset.Now; - var component = new EventCountingComponent(); - Action setter = (_) => value = _; - - var binder = EventCallback.Factory.CreateBinder(component, setter, value); - - var expectedValue = new DateTime(2018, 3, 4, 1, 2, 3); - - // Act - await binder.InvokeAsync(new ChangeEventArgs() { Value = expectedValue.ToString(), }); - - Assert.Equal(expectedValue, value); - Assert.Equal(1, component.Count); - } - - [Fact] - public async Task CreateBinder_NullableDateTimeOffset() - { - // Arrange - var value = (DateTimeOffset?)DateTimeOffset.Now; - var component = new EventCountingComponent(); - Action setter = (_) => value = _; - - var binder = EventCallback.Factory.CreateBinder(component, setter, value); - - var expectedValue = new DateTime(2018, 3, 4, 1, 2, 3); - - // Act - await binder.InvokeAsync(new ChangeEventArgs() { Value = expectedValue.ToString(), }); - - Assert.Equal(expectedValue, value); - Assert.Equal(1, component.Count); - } - - [Fact] - public async Task CreateBinder_DateTimeOffset_Format() - { - // Arrange - var value = DateTimeOffset.Now; - var component = new EventCountingComponent(); - Action setter = (_) => value = _; - var format = "ddd yyyy-MM-dd"; - - var binder = EventCallback.Factory.CreateBinder(component, setter, value, format); - - var expectedValue = new DateTime(2018, 3, 4); - - // Act - await binder.InvokeAsync(new ChangeEventArgs() { Value = expectedValue.ToString(format), }); - - Assert.Equal(expectedValue, value); - Assert.Equal(1, component.Count); - } - - [Fact] - public async Task CreateBinder_NullableDateTimeOffset_Format() - { - // Arrange - var value = (DateTimeOffset?)DateTimeOffset.Now; - var component = new EventCountingComponent(); - Action setter = (_) => value = _; - var format = "ddd yyyy-MM-dd"; - - var binder = EventCallback.Factory.CreateBinder(component, setter, value, format); - - var expectedValue = new DateTime(2018, 3, 4); - - // Act - await binder.InvokeAsync(new ChangeEventArgs() { Value = expectedValue.ToString(format), }); - - Assert.Equal(expectedValue, value); - Assert.Equal(1, component.Count); - } - - // This uses a type converter - [Fact] - public async Task CreateBinder_Guid() - { - // Arrange - var value = Guid.NewGuid(); - var component = new EventCountingComponent(); - Action setter = (_) => value = _; - - var binder = EventCallback.Factory.CreateBinder(component, setter, value); - - var expectedValue = Guid.NewGuid(); - - // Act - await binder.InvokeAsync(new ChangeEventArgs() { Value = expectedValue.ToString(), }); - - Assert.Equal(expectedValue, value); - Assert.Equal(1, component.Count); - } - - // This uses a type converter - [Fact] - public async Task CreateBinder_NullableGuid() - { - // Arrange - var value = (Guid?)Guid.NewGuid(); - var component = new EventCountingComponent(); - Action setter = (_) => value = _; - - var binder = EventCallback.Factory.CreateBinder(component, setter, value); - - var expectedValue = Guid.NewGuid(); - - // Act - await binder.InvokeAsync(new ChangeEventArgs() { Value = expectedValue.ToString(), }); - - Assert.Equal(expectedValue, value); - Assert.Equal(1, component.Count); - } - - [Fact] - public async Task CreateBinder_CustomTypeConverter() - { - // Arrange - var value = new SecretMessage() { Message = "A message", }; - var component = new EventCountingComponent(); - Action setter = (_) => value = _; - - var binder = EventCallback.Factory.CreateBinder(component, setter, value); - - var expectedValue = new SecretMessage() { Message = "TypeConverter may be old, but it still works!", }; - - // Act - await binder.InvokeAsync(new ChangeEventArgs() { Value = expectedValue.ToString(), }); - - Assert.Equal(expectedValue.Message, value.Message); - Assert.Equal(1, component.Count); - } - - [Fact] - public void CreateBinder_GenericWithoutTypeConverter_Throws() - { - var value = new ClassWithoutTypeConverter(); - var component = new EventCountingComponent(); - Action setter = (_) => value = _; - - var ex = Assert.Throws(() => EventCallback.Factory.CreateBinder(component, setter, value)); - - Assert.Equal( - $"The type '{typeof(ClassWithoutTypeConverter).FullName}' does not have an associated TypeConverter that supports conversion from a string. " + - $"Apply 'TypeConverterAttribute' to the type to register a converter.", - ex.Message); - } - - [Fact] - [ReplaceCulture("fr-FR", "fr-FR")] - public async Task CreateBinder_NumericType_WithCurrentCulture() - { - // Arrange - var value = 17_000; - var component = new EventCountingComponent(); - Action setter = (_) => value = _; - - var binder = EventCallback.Factory.CreateBinder(component, setter, value, culture: null); - - var expectedValue = 42_000; - - // Act - await binder.InvokeAsync(new ChangeEventArgs() { Value = "42 000,00", }); - - Assert.Equal(expectedValue, value); - Assert.Equal(1, component.Count); - } - - [Fact] - public async Task CreateBinder_NumericType_WithInvariantCulture() - { - // Arrange - var value = 17_000; - var component = new EventCountingComponent(); - Action setter = (_) => value = _; - - var binder = EventCallback.Factory.CreateBinder(component, setter, value, CultureInfo.InvariantCulture); - - var expectedValue = 42_000; - - // Act - await binder.InvokeAsync(new ChangeEventArgs() { Value = "42,000.00", }); - - Assert.Equal(expectedValue, value); - Assert.Equal(1, component.Count); - } - - private class EventCountingComponent : IComponent, IHandleEvent - { - public int Count; - - public Task HandleEventAsync(EventCallbackWorkItem item, object arg) - { - Count++; - return item.InvokeAsync(arg); - } - - public void Attach(RenderHandle renderHandle) - { - throw new System.NotImplementedException(); - } - - public Task SetParametersAsync(ParameterView parameters) - { - throw new System.NotImplementedException(); - } - } - - private class ClassWithoutTypeConverter - { - } - - [TypeConverter(typeof(SecretMessageTypeConverter))] - private class SecretMessage - { - public string Message { get; set; } - - public override string ToString() - { - return Message; - } - } - - private class SecretMessageTypeConverter : TypeConverter - { - public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) - { - if (sourceType == typeof(string)) - { - return true; - } - - return false; - } - public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) - { - if (value is string message) - { - return new SecretMessage() { Message = message, }; - } - - return null; - } - } - } -} diff --git a/src/Components/Components/test/EventCallbackFactoryTest.cs b/src/Components/Components/test/EventCallbackFactoryTest.cs deleted file mode 100644 index 69b7bfa748..0000000000 --- a/src/Components/Components/test/EventCallbackFactoryTest.cs +++ /dev/null @@ -1,654 +0,0 @@ -// 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 Xunit; - -namespace Microsoft.AspNetCore.Components -{ - public class EventCallbackFactoryTest - { - [Fact] - public void Create_EventCallback_ReturnsInput() - { - // Arrange - var component = new EventComponent(); - var @delegate = (Action)component.SomeAction; - var input = new EventCallback(component, @delegate); - - var anotherComponent = new EventComponent(); - - // Act - var callback = EventCallback.Factory.Create(anotherComponent, input); - - // Assert - Assert.Same(@delegate, callback.Delegate); - Assert.Same(component, callback.Receiver); - Assert.False(callback.RequiresExplicitReceiver); - } - - [Fact] - public void Create_Action_AlreadyBoundToReceiver() - { - // Arrange - var component = new EventComponent(); - var @delegate = (Action)component.SomeAction; - - // Act - var callback = EventCallback.Factory.Create(component, @delegate); - - // Assert - Assert.Same(@delegate, callback.Delegate); - Assert.Same(component, callback.Receiver); - Assert.False(callback.RequiresExplicitReceiver); - } - - [Fact] - public void Create_Action_DifferentReceiver() - { - // Arrange - var component = new EventComponent(); - var @delegate = (Action)component.SomeAction; - - var anotherComponent = new EventComponent(); - - // Act - var callback = EventCallback.Factory.Create(anotherComponent, @delegate); - - // Assert - Assert.Same(@delegate, callback.Delegate); - Assert.Same(component, callback.Receiver); - Assert.False(callback.RequiresExplicitReceiver); - } - - [Fact] - public void Create_Action_Unbound() - { - // Arrange - var component = new EventComponent(); - var @delegate = (Action)(() => { }); - - var anotherComponent = new EventComponent(); - - // Act - var callback = EventCallback.Factory.Create(anotherComponent, @delegate); - - // Assert - Assert.Same(@delegate, callback.Delegate); - Assert.Same(anotherComponent, callback.Receiver); - Assert.True(callback.RequiresExplicitReceiver); - } - - [Fact] - public void Create_Action_Null() - { - // Arrange - var component = new EventComponent(); - - // Act - var callback = EventCallback.Factory.Create(component, (Action)null); - - // Assert - Assert.Null(callback.Delegate); - Assert.Same(component, callback.Receiver); - Assert.True(callback.RequiresExplicitReceiver); - } - - [Fact] - public void Create_ActionT_AlreadyBoundToReceiver() - { - // Arrange - var component = new EventComponent(); - var @delegate = (Action)component.SomeActionOfT; - - // Act - var callback = EventCallback.Factory.Create(component, @delegate); - - // Assert - Assert.Same(@delegate, callback.Delegate); - Assert.Same(component, callback.Receiver); - Assert.False(callback.RequiresExplicitReceiver); - } - - [Fact] - public void Create_ActionT_DifferentReceiver() - { - // Arrange - var component = new EventComponent(); - var @delegate = (Action)component.SomeActionOfT; - - var anotherComponent = new EventComponent(); - - // Act - var callback = EventCallback.Factory.Create(anotherComponent, @delegate); - - // Assert - Assert.Same(@delegate, callback.Delegate); - Assert.Same(component, callback.Receiver); - Assert.False(callback.RequiresExplicitReceiver); - } - - [Fact] - public void Create_ActionT_Unbound() - { - // Arrange - var component = new EventComponent(); - var @delegate = (Action)((s) => { }); - - var anotherComponent = new EventComponent(); - - // Act - var callback = EventCallback.Factory.Create(anotherComponent, @delegate); - - // Assert - Assert.Same(@delegate, callback.Delegate); - Assert.Same(anotherComponent, callback.Receiver); - Assert.True(callback.RequiresExplicitReceiver); - } - - [Fact] - public void Create_ActionT_Null() - { - // Arrange - var component = new EventComponent(); - - // Act - var callback = EventCallback.Factory.Create(component, (Action)null); - - // Assert - Assert.Null(callback.Delegate); - Assert.Same(component, callback.Receiver); - Assert.True(callback.RequiresExplicitReceiver); - } - - [Fact] - public void Create_FuncTask_AlreadyBoundToReceiver() - { - // Arrange - var component = new EventComponent(); - var @delegate = (Func)component.SomeFuncTask; - - // Act - var callback = EventCallback.Factory.Create(component, @delegate); - - // Assert - Assert.Same(@delegate, callback.Delegate); - Assert.Same(component, callback.Receiver); - Assert.False(callback.RequiresExplicitReceiver); - } - - [Fact] - public void Create_FuncTask_DifferentReceiver() - { - // Arrange - var component = new EventComponent(); - var @delegate = (Func)component.SomeFuncTask; - - var anotherComponent = new EventComponent(); - - // Act - var callback = EventCallback.Factory.Create(anotherComponent, @delegate); - - // Assert - Assert.Same(@delegate, callback.Delegate); - Assert.Same(component, callback.Receiver); - Assert.False(callback.RequiresExplicitReceiver); - } - - [Fact] - public void Create_FuncTask_Unbound() - { - // Arrange - var component = new EventComponent(); - var @delegate = (Func)(() => Task.CompletedTask); - - var anotherComponent = new EventComponent(); - - // Act - var callback = EventCallback.Factory.Create(anotherComponent, @delegate); - - // Assert - Assert.Same(@delegate, callback.Delegate); - Assert.Same(anotherComponent, callback.Receiver); - Assert.True(callback.RequiresExplicitReceiver); - } - - [Fact] - public void Create_FuncTTask_AlreadyBoundToReceiver() - { - // Arrange - var component = new EventComponent(); - var @delegate = (Func)component.SomeFuncTTask; - - // Act - var callback = EventCallback.Factory.Create(component, @delegate); - - // Assert - Assert.Same(@delegate, callback.Delegate); - Assert.Same(component, callback.Receiver); - Assert.False(callback.RequiresExplicitReceiver); - } - - [Fact] - public void Create_FuncTask_Null() - { - // Arrange - var component = new EventComponent(); - - // Act - var callback = EventCallback.Factory.Create(component, (Func)null); - - // Assert - Assert.Null(callback.Delegate); - Assert.Same(component, callback.Receiver); - Assert.True(callback.RequiresExplicitReceiver); - } - - [Fact] - public void Create_FuncTTask_DifferentReceiver() - { - // Arrange - var component = new EventComponent(); - var @delegate = (Func)component.SomeFuncTTask; - - var anotherComponent = new EventComponent(); - - // Act - var callback = EventCallback.Factory.Create(anotherComponent, @delegate); - - // Assert - Assert.Same(@delegate, callback.Delegate); - Assert.Same(component, callback.Receiver); - Assert.False(callback.RequiresExplicitReceiver); - } - - [Fact] - public void Create_FuncTTask_Unbound() - { - // Arrange - var component = new EventComponent(); - var @delegate = (Func)((s) => Task.CompletedTask); - - var anotherComponent = new EventComponent(); - - // Act - var callback = EventCallback.Factory.Create(anotherComponent, @delegate); - - // Assert - Assert.Same(@delegate, callback.Delegate); - Assert.Same(anotherComponent, callback.Receiver); - Assert.True(callback.RequiresExplicitReceiver); - } - - [Fact] - public void Create_FuncTTask_Null() - { - // Arrange - var component = new EventComponent(); - - // Act - var callback = EventCallback.Factory.Create(component, (Func)null); - - // Assert - Assert.Null(callback.Delegate); - Assert.Same(component, callback.Receiver); - Assert.True(callback.RequiresExplicitReceiver); - } - - [Fact] - public void CreateT_EventCallback_ReturnsInput() - { - // Arrange - var component = new EventComponent(); - var @delegate = (Action)component.SomeAction; - var input = new EventCallback(component, @delegate); - - var anotherComponent = new EventComponent(); - - // Act - var callback = EventCallback.Factory.Create(anotherComponent, input); - - // Assert - Assert.Same(@delegate, callback.Delegate); - Assert.Same(component, callback.Receiver); - Assert.False(callback.RequiresExplicitReceiver); - } - - [Fact] - public void CreateT_Action_AlreadyBoundToReceiver() - { - // Arrange - var component = new EventComponent(); - var @delegate = (Action)component.SomeAction; - - // Act - var callback = EventCallback.Factory.Create(component, @delegate); - - // Assert - Assert.Same(@delegate, callback.Delegate); - Assert.Same(component, callback.Receiver); - Assert.False(callback.RequiresExplicitReceiver); - } - - [Fact] - public void CreateT_Action_DifferentReceiver() - { - // Arrange - var component = new EventComponent(); - var @delegate = (Action)component.SomeAction; - - var anotherComponent = new EventComponent(); - - // Act - var callback = EventCallback.Factory.Create(anotherComponent, @delegate); - - // Assert - Assert.Same(@delegate, callback.Delegate); - Assert.Same(component, callback.Receiver); - Assert.False(callback.RequiresExplicitReceiver); - } - - [Fact] - public void CreateT_Action_Unbound() - { - // Arrange - var component = new EventComponent(); - var @delegate = (Action)(() => { }); - - var anotherComponent = new EventComponent(); - - // Act - var callback = EventCallback.Factory.Create(anotherComponent, @delegate); - - // Assert - Assert.Same(@delegate, callback.Delegate); - Assert.Same(anotherComponent, callback.Receiver); - Assert.True(callback.RequiresExplicitReceiver); - } - - [Fact] - public void CreateT_Action_Null() - { - // Arrange - var component = new EventComponent(); - - // Act - var callback = EventCallback.Factory.Create(component, (Action)null); - - // Assert - Assert.Null(callback.Delegate); - Assert.Same(component, callback.Receiver); - Assert.True(callback.RequiresExplicitReceiver); - } - - [Fact] - public void CreateT_ActionT_AlreadyBoundToReceiver() - { - // Arrange - var component = new EventComponent(); - var @delegate = (Action)component.SomeActionOfT; - - // Act - var callback = EventCallback.Factory.Create(component, @delegate); - - // Assert - Assert.Same(@delegate, callback.Delegate); - Assert.Same(component, callback.Receiver); - Assert.False(callback.RequiresExplicitReceiver); - } - - [Fact] - public void CreateT_ActionT_DifferentReceiver() - { - // Arrange - var component = new EventComponent(); - var @delegate = (Action)component.SomeActionOfT; - - var anotherComponent = new EventComponent(); - - // Act - var callback = EventCallback.Factory.Create(anotherComponent, @delegate); - - // Assert - Assert.Same(@delegate, callback.Delegate); - Assert.Same(component, callback.Receiver); - Assert.False(callback.RequiresExplicitReceiver); - } - - [Fact] - public void CreateT_ActionT_Null() - { - // Arrange - var component = new EventComponent(); - - // Act - var callback = EventCallback.Factory.Create(component, (Action)null); - - // Assert - Assert.Null(callback.Delegate); - Assert.Same(component, callback.Receiver); - Assert.True(callback.RequiresExplicitReceiver); - } - - [Fact] - public void CreateT_ActionT_Unbound() - { - // Arrange - var component = new EventComponent(); - var @delegate = (Action)((s) => { }); - - var anotherComponent = new EventComponent(); - - // Act - var callback = EventCallback.Factory.Create(anotherComponent, @delegate); - - // Assert - Assert.Same(@delegate, callback.Delegate); - Assert.Same(anotherComponent, callback.Receiver); - Assert.True(callback.RequiresExplicitReceiver); - } - - [Fact] - public void CreateT_FuncTask_AlreadyBoundToReceiver() - { - // Arrange - var component = new EventComponent(); - var @delegate = (Func)component.SomeFuncTask; - - // Act - var callback = EventCallback.Factory.Create(component, @delegate); - - // Assert - Assert.Same(@delegate, callback.Delegate); - Assert.Same(component, callback.Receiver); - Assert.False(callback.RequiresExplicitReceiver); - } - - [Fact] - public void CreateT_FuncTask_DifferentReceiver() - { - // Arrange - var component = new EventComponent(); - var @delegate = (Func)component.SomeFuncTask; - - var anotherComponent = new EventComponent(); - - // Act - var callback = EventCallback.Factory.Create(anotherComponent, @delegate); - - // Assert - Assert.Same(@delegate, callback.Delegate); - Assert.Same(component, callback.Receiver); - Assert.False(callback.RequiresExplicitReceiver); - } - - [Fact] - public void CreateT_FuncTask_Unbound() - { - // Arrange - var component = new EventComponent(); - var @delegate = (Func)(() => Task.CompletedTask); - - var anotherComponent = new EventComponent(); - - // Act - var callback = EventCallback.Factory.Create(anotherComponent, @delegate); - - // Assert - Assert.Same(@delegate, callback.Delegate); - Assert.Same(anotherComponent, callback.Receiver); - Assert.True(callback.RequiresExplicitReceiver); - } - - [Fact] - public void CreateT_FuncTask_Null() - { - // Arrange - var component = new EventComponent(); - - // Act - var callback = EventCallback.Factory.Create(component, (Func)null); - - // Assert - Assert.Null(callback.Delegate); - Assert.Same(component, callback.Receiver); - Assert.True(callback.RequiresExplicitReceiver); - } - - [Fact] - public void CreateT_FuncTTask_AlreadyBoundToReceiver() - { - // Arrange - var component = new EventComponent(); - var @delegate = (Func)component.SomeFuncTTask; - - // Act - var callback = EventCallback.Factory.Create(component, @delegate); - - // Assert - Assert.Same(@delegate, callback.Delegate); - Assert.Same(component, callback.Receiver); - Assert.False(callback.RequiresExplicitReceiver); - } - - [Fact] - public void CreateT_FuncTTask_DifferentReceiver() - { - // Arrange - var component = new EventComponent(); - var @delegate = (Func)component.SomeFuncTTask; - - var anotherComponent = new EventComponent(); - - // Act - var callback = EventCallback.Factory.Create(anotherComponent, @delegate); - - // Assert - Assert.Same(@delegate, callback.Delegate); - Assert.Same(component, callback.Receiver); - Assert.False(callback.RequiresExplicitReceiver); - } - - [Fact] - public void CreateT_FuncTTask_Unbound() - { - // Arrange - var component = new EventComponent(); - var @delegate = (Func)((s) => Task.CompletedTask); - - var anotherComponent = new EventComponent(); - - // Act - var callback = EventCallback.Factory.Create(anotherComponent, @delegate); - - // Assert - Assert.Same(@delegate, callback.Delegate); - Assert.Same(anotherComponent, callback.Receiver); - Assert.True(callback.RequiresExplicitReceiver); - } - - [Fact] - public void CreateT_FuncTTask_Null() - { - // Arrange - var component = new EventComponent(); - - // Act - var callback = EventCallback.Factory.Create(component, (Func)null); - - // Assert - Assert.Null(callback.Delegate); - Assert.Same(component, callback.Receiver); - Assert.True(callback.RequiresExplicitReceiver); - } - - [Fact] - public void CreateInferred_ActionT() - { - // Arrange - var component = new EventComponent(); - var @delegate = (Action)((s) => { }); - - // Act - var callback = EventCallback.Factory.CreateInferred(component, @delegate, "hi"); - - // Assert - Assert.Same(@delegate, callback.Delegate); - Assert.Same(component, callback.Receiver); - Assert.True(callback.RequiresExplicitReceiver); - } - - [Fact] - public void CreateInferred_FuncTTask() - { - // Arrange - var component = new EventComponent(); - var @delegate = (Func)((s) => Task.CompletedTask); - - // Act - var callback = EventCallback.Factory.CreateInferred(component, @delegate, "hi"); - - // Assert - Assert.Same(@delegate, callback.Delegate); - Assert.Same(component, callback.Receiver); - Assert.True(callback.RequiresExplicitReceiver); - } - - private class EventComponent : IComponent, IHandleEvent - { - public void SomeAction() - { - } - - public void SomeActionOfT(string e) - { - } - - public Task SomeFuncTask() - { - return Task.CompletedTask; - } - - public Task SomeFuncTTask(string s) - { - return Task.CompletedTask; - } - - public void Attach(RenderHandle renderHandle) - { - throw new NotImplementedException(); - } - - public Task HandleEventAsync(EventCallbackWorkItem item, object arg) - { - throw new NotImplementedException(); - } - - public Task SetParametersAsync(ParameterView parameters) - { - throw new NotImplementedException(); - } - } - } -} diff --git a/src/Components/Components/test/EventCallbackTest.cs b/src/Components/Components/test/EventCallbackTest.cs deleted file mode 100644 index 25405c2180..0000000000 --- a/src/Components/Components/test/EventCallbackTest.cs +++ /dev/null @@ -1,457 +0,0 @@ -// 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.Text; -using System.Threading.Tasks; -using Xunit; - -namespace Microsoft.AspNetCore.Components -{ - public class EventCallbackTest - { - [Fact] - public async Task EventCallback_Default() - { - // Arrange - var callback = default(EventCallback); - - // Act & Assert (Does not throw) - await callback.InvokeAsync(null); - } - - [Fact] - public async Task EventCallbackOfT_Default() - { - // Arrange - var callback = default(EventCallback); - - // Act & Assert (Does not throw) - await callback.InvokeAsync(null); - } - - - [Fact] - public async Task EventCallback_NullReceiver() - { - // Arrange - int runCount = 0; - var callback = new EventCallback(null, (Action)(() => runCount++)); - - // Act - await callback.InvokeAsync(null); - - - // Assert - Assert.Equal(1, runCount); - } - - [Fact] - public async Task EventCallbackOfT_NullReceiver() - { - // Arrange - int runCount = 0; - var callback = new EventCallback(null, (Action)(() => runCount++)); - - // Act - await callback.InvokeAsync(null); - - - // Assert - Assert.Equal(1, runCount); - } - - [Fact] - public async Task EventCallback_Action_Null() - { - // Arrange - var component = new EventCountingComponent(); - - int runCount = 0; - var callback = new EventCallback(component, (Action)(() => runCount++)); - - // Act - await callback.InvokeAsync(null); - - - // Assert - Assert.Equal(1, runCount); - Assert.Equal(1, component.Count); - } - - [Fact] - public async Task EventCallback_Action_IgnoresArg() - { - // Arrange - var component = new EventCountingComponent(); - - int runCount = 0; - var callback = new EventCallback(component, (Action)(() => runCount++)); - - // Act - await callback.InvokeAsync(new EventArgs()); - - - // Assert - Assert.Equal(1, runCount); - Assert.Equal(1, component.Count); - } - - [Fact] - public async Task EventCallback_ActionT_Null() - { - // Arrange - var component = new EventCountingComponent(); - - int runCount = 0; - EventArgs arg = null; - var callback = new EventCallback(component, (Action)((e) => { arg = e; runCount++; })); - - // Act - await callback.InvokeAsync(null); - - - // Assert - Assert.Null(arg); - Assert.Equal(1, runCount); - Assert.Equal(1, component.Count); - } - - [Fact] - public async Task EventCallback_ActionT_Arg() - { - // Arrange - var component = new EventCountingComponent(); - - int runCount = 0; - EventArgs arg = null; - var callback = new EventCallback(component, (Action)((e) => { arg = e; runCount++; })); - - // Act - await callback.InvokeAsync(new EventArgs()); - - - // Assert - Assert.NotNull(arg); - Assert.Equal(1, runCount); - Assert.Equal(1, component.Count); - } - - [Fact] - public async Task EventCallback_ActionT_Arg_ValueType() - { - // Arrange - var component = new EventCountingComponent(); - - int runCount = 0; - int arg = -1; - var callback = new EventCallback(component, (Action)((e) => { arg = e; runCount++; })); - - // Act - await callback.InvokeAsync(17); - - - // Assert - Assert.Equal(17, arg); - Assert.Equal(1, runCount); - Assert.Equal(1, component.Count); - } - - [Fact] - public async Task EventCallback_ActionT_ArgMismatch() - { - // Arrange - var component = new EventCountingComponent(); - - int runCount = 0; - EventArgs arg = null; - var callback = new EventCallback(component, (Action)((e) => { arg = e; runCount++; })); - - // Act & Assert - await Assert.ThrowsAsync(() => - { - return callback.InvokeAsync(new StringBuilder()); - }); - } - - [Fact] - public async Task EventCallback_FuncTask_Null() - { - // Arrange - var component = new EventCountingComponent(); - - int runCount = 0; - var callback = new EventCallback(component, (Func)(() => { runCount++; return Task.CompletedTask; })); - - // Act - await callback.InvokeAsync(null); - - - // Assert - Assert.Equal(1, runCount); - Assert.Equal(1, component.Count); - } - - [Fact] - public async Task EventCallback_FuncTask_IgnoresArg() - { - // Arrange - var component = new EventCountingComponent(); - - int runCount = 0; - var callback = new EventCallback(component, (Func)(() => { runCount++; return Task.CompletedTask; })); - - // Act - await callback.InvokeAsync(new EventArgs()); - - - // Assert - Assert.Equal(1, runCount); - Assert.Equal(1, component.Count); - } - - [Fact] - public async Task EventCallback_FuncTTask_Null() - { - // Arrange - var component = new EventCountingComponent(); - - int runCount = 0; - EventArgs arg = null; - var callback = new EventCallback(component, (Func)((e) => { arg = e; runCount++; return Task.CompletedTask; })); - - // Act - await callback.InvokeAsync(null); - - - // Assert - Assert.Null(arg); - Assert.Equal(1, runCount); - Assert.Equal(1, component.Count); - } - - [Fact] - public async Task EventCallback_FuncTTask_Arg() - { - // Arrange - var component = new EventCountingComponent(); - - int runCount = 0; - EventArgs arg = null; - var callback = new EventCallback(component, (Func)((e) => { arg = e; runCount++; return Task.CompletedTask; })); - - // Act - await callback.InvokeAsync(new EventArgs()); - - - // Assert - Assert.NotNull(arg); - Assert.Equal(1, runCount); - Assert.Equal(1, component.Count); - } - - [Fact] - public async Task EventCallback_FuncTTask_Arg_ValueType() - { - // Arrange - var component = new EventCountingComponent(); - - int runCount = 0; - int arg = -1; - var callback = new EventCallback(component, (Func)((e) => { arg = e; runCount++; return Task.CompletedTask; })); - - // Act - await callback.InvokeAsync(17); - - - // Assert - Assert.Equal(17, arg); - Assert.Equal(1, runCount); - Assert.Equal(1, component.Count); - } - - [Fact] - public async Task EventCallback_FuncTTask_ArgMismatch() - { - // Arrange - var component = new EventCountingComponent(); - - int runCount = 0; - EventArgs arg = null; - var callback = new EventCallback(component, (Func)((e) => { arg = e; runCount++; return Task.CompletedTask; })); - - // Act & Assert - await Assert.ThrowsAsync(() => - { - return callback.InvokeAsync(new StringBuilder()); - }); - } - - [Fact] - public async Task EventCallbackOfT_Action_Null() - { - // Arrange - var component = new EventCountingComponent(); - - int runCount = 0; - var callback = new EventCallback(component, (Action)(() => runCount++)); - - // Act - await callback.InvokeAsync(null); - - - // Assert - Assert.Equal(1, runCount); - Assert.Equal(1, component.Count); - } - - [Fact] - public async Task EventCallbackOfT_Action_IgnoresArg() - { - // Arrange - var component = new EventCountingComponent(); - - int runCount = 0; - var callback = new EventCallback(component, (Action)(() => runCount++)); - - // Act - await callback.InvokeAsync(new EventArgs()); - - - // Assert - Assert.Equal(1, runCount); - Assert.Equal(1, component.Count); - } - - [Fact] - public async Task EventCallbackOfT_ActionT_Null() - { - // Arrange - var component = new EventCountingComponent(); - - int runCount = 0; - EventArgs arg = null; - var callback = new EventCallback(component, (Action)((e) => { arg = e; runCount++; })); - - // Act - await callback.InvokeAsync(null); - - - // Assert - Assert.Null(arg); - Assert.Equal(1, runCount); - Assert.Equal(1, component.Count); - } - - [Fact] - public async Task EventCallbackOfT_ActionT_Arg() - { - // Arrange - var component = new EventCountingComponent(); - - int runCount = 0; - EventArgs arg = null; - var callback = new EventCallback(component, (Action)((e) => { arg = e; runCount++; })); - - // Act - await callback.InvokeAsync(new EventArgs()); - - - // Assert - Assert.NotNull(arg); - Assert.Equal(1, runCount); - Assert.Equal(1, component.Count); - } - - [Fact] - public async Task EventCallbackOfT_FuncTask_Null() - { - // Arrange - var component = new EventCountingComponent(); - - int runCount = 0; - var callback = new EventCallback(component, (Func)(() => { runCount++; return Task.CompletedTask; })); - - // Act - await callback.InvokeAsync(null); - - - // Assert - Assert.Equal(1, runCount); - Assert.Equal(1, component.Count); - } - - [Fact] - public async Task EventCallbackOfT_FuncTask_IgnoresArg() - { - // Arrange - var component = new EventCountingComponent(); - - int runCount = 0; - var callback = new EventCallback(component, (Func)(() => { runCount++; return Task.CompletedTask; })); - - // Act - await callback.InvokeAsync(new EventArgs()); - - - // Assert - Assert.Equal(1, runCount); - Assert.Equal(1, component.Count); - } - - [Fact] - public async Task EventCallbackOfT_FuncTTask_Null() - { - // Arrange - var component = new EventCountingComponent(); - - int runCount = 0; - EventArgs arg = null; - var callback = new EventCallback(component, (Func)((e) => { arg = e; runCount++; return Task.CompletedTask; })); - - // Act - await callback.InvokeAsync(null); - - - // Assert - Assert.Null(arg); - Assert.Equal(1, runCount); - Assert.Equal(1, component.Count); - } - - [Fact] - public async Task EventCallbackOfT_FuncTTask_Arg() - { - // Arrange - var component = new EventCountingComponent(); - - int runCount = 0; - EventArgs arg = null; - var callback = new EventCallback(component, (Func)((e) => { arg = e; runCount++; return Task.CompletedTask; })); - - // Act - await callback.InvokeAsync(new EventArgs()); - - - // Assert - Assert.NotNull(arg); - Assert.Equal(1, runCount); - Assert.Equal(1, component.Count); - } - - private class EventCountingComponent : IComponent, IHandleEvent - { - public int Count; - - public Task HandleEventAsync(EventCallbackWorkItem item, object arg) - { - Count++; - return item.InvokeAsync(arg); - } - - public void Attach(RenderHandle renderHandle) => throw new NotImplementedException(); - - public Task SetParametersAsync(ParameterView parameters) => throw new NotImplementedException(); - } - } -} diff --git a/src/Components/Components/test/LayoutViewTest.cs b/src/Components/Components/test/LayoutViewTest.cs deleted file mode 100644 index 592cb7e62d..0000000000 --- a/src/Components/Components/test/LayoutViewTest.cs +++ /dev/null @@ -1,326 +0,0 @@ -// 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.Collections.Generic; -using System.Linq; -using Microsoft.AspNetCore.Components.Rendering; -using Microsoft.AspNetCore.Components.RenderTree; -using Microsoft.AspNetCore.Components.Test.Helpers; -using Xunit; - -namespace Microsoft.AspNetCore.Components.Test -{ - public class LayoutViewTest - { - private readonly TestRenderer _renderer; - private readonly LayoutView _layoutViewComponent; - private readonly int _layoutViewComponentId; - - public LayoutViewTest() - { - _renderer = new TestRenderer(); - _layoutViewComponent = new LayoutView(); - _layoutViewComponentId = _renderer.AssignRootComponentId(_layoutViewComponent); - } - - [Fact] - public void GivenNoParameters_RendersNothing() - { - // Arrange/Act - var setParametersTask = _renderer.Dispatcher.InvokeAsync(() => _layoutViewComponent.SetParametersAsync(ParameterView.Empty)); - Assert.True(setParametersTask.IsCompletedSuccessfully); - var frames = _renderer.GetCurrentRenderTreeFrames(_layoutViewComponentId).AsEnumerable(); - - // Assert - Assert.Single(_renderer.Batches); - Assert.Empty(frames); - } - - [Fact] - public void GivenContentButNoLayout_RendersContent() - { - // Arrange/Act - var setParametersTask = _renderer.Dispatcher.InvokeAsync(() => _layoutViewComponent.SetParametersAsync(ParameterView.FromDictionary(new Dictionary - { - { nameof(LayoutView.ChildContent), (RenderFragment)(builder => { - builder.AddContent(123, "Hello"); - builder.AddContent(456, "Goodbye"); - })} - }))); - Assert.True(setParametersTask.IsCompletedSuccessfully); - var frames = _renderer.GetCurrentRenderTreeFrames(_layoutViewComponentId).AsEnumerable(); - - // Assert - Assert.Single(_renderer.Batches); - Assert.Collection(frames, - frame => AssertFrame.Text(frame, "Hello", 123), - frame => AssertFrame.Text(frame, "Goodbye", 456)); - } - - [Fact] - public void GivenLayoutButNoContent_RendersLayoutWithEmptyBody() - { - // Arrange/Act - var setParametersTask = _renderer.Dispatcher.InvokeAsync(() => _layoutViewComponent.SetParametersAsync(ParameterView.FromDictionary(new Dictionary - { - { nameof(LayoutView.Layout), typeof(RootLayout) } - }))); - - // Assert - Assert.True(setParametersTask.IsCompletedSuccessfully); - var batch = _renderer.Batches.Single(); - - var layoutViewFrames = _renderer.GetCurrentRenderTreeFrames(_layoutViewComponentId).AsEnumerable(); - Assert.Collection(layoutViewFrames, - frame => AssertFrame.Component(frame, subtreeLength: 2, sequence: 0), - frame => AssertFrame.Attribute(frame, nameof(LayoutComponentBase.Body), sequence: 1)); - - var rootLayoutComponentId = batch.GetComponentFrames().Single().ComponentId; - var rootLayoutFrames = _renderer.GetCurrentRenderTreeFrames(rootLayoutComponentId).AsEnumerable(); - Assert.Collection(rootLayoutFrames, - frame => AssertFrame.Text(frame, "RootLayout starts here", sequence: 0), - frame => AssertFrame.Region(frame, subtreeLength: 1), // i.e., empty region - frame => AssertFrame.Text(frame, "RootLayout ends here", sequence: 2)); - } - - [Fact] - public void RendersContentInsideLayout() - { - // Arrange/Act - var setParametersTask = _renderer.Dispatcher.InvokeAsync(() => _layoutViewComponent.SetParametersAsync(ParameterView.FromDictionary(new Dictionary - { - { nameof(LayoutView.Layout), typeof(RootLayout) }, - { nameof(LayoutView.ChildContent), (RenderFragment)(builder => { - builder.AddContent(123, "Hello"); - builder.AddContent(456, "Goodbye"); - })} - }))); - - // Assert - Assert.True(setParametersTask.IsCompletedSuccessfully); - var batch = _renderer.Batches.Single(); - - var layoutViewFrames = _renderer.GetCurrentRenderTreeFrames(_layoutViewComponentId).AsEnumerable(); - Assert.Collection(layoutViewFrames, - frame => AssertFrame.Component(frame, subtreeLength: 2, sequence: 0), - frame => AssertFrame.Attribute(frame, nameof(LayoutComponentBase.Body), sequence: 1)); - - var rootLayoutComponentId = batch.GetComponentFrames().Single().ComponentId; - var rootLayoutFrames = _renderer.GetCurrentRenderTreeFrames(rootLayoutComponentId).AsEnumerable(); - Assert.Collection(rootLayoutFrames, - frame => AssertFrame.Text(frame, "RootLayout starts here", sequence: 0), - frame => AssertFrame.Region(frame, subtreeLength: 3), - frame => AssertFrame.Text(frame, "Hello", sequence: 123), - frame => AssertFrame.Text(frame, "Goodbye", sequence: 456), - frame => AssertFrame.Text(frame, "RootLayout ends here", sequence: 2)); - } - - [Fact] - public void RendersContentInsideNestedLayout() - { - // Arrange/Act - var setParametersTask = _renderer.Dispatcher.InvokeAsync(() => _layoutViewComponent.SetParametersAsync(ParameterView.FromDictionary(new Dictionary - { - { nameof(LayoutView.Layout), typeof(NestedLayout) }, - { nameof(LayoutView.ChildContent), (RenderFragment)(builder => { - builder.AddContent(123, "Hello"); - builder.AddContent(456, "Goodbye"); - })} - }))); - - // Assert - Assert.True(setParametersTask.IsCompletedSuccessfully); - var batch = _renderer.Batches.Single(); - - var layoutViewFrames = _renderer.GetCurrentRenderTreeFrames(_layoutViewComponentId).AsEnumerable(); - Assert.Collection(layoutViewFrames, - frame => AssertFrame.Component(frame, subtreeLength: 2, sequence: 0), - frame => AssertFrame.Attribute(frame, nameof(LayoutComponentBase.Body), sequence: 1)); - - var rootLayoutComponentId = batch.GetComponentFrames().Single().ComponentId; - var rootLayoutFrames = _renderer.GetCurrentRenderTreeFrames(rootLayoutComponentId).AsEnumerable(); - Assert.Collection(rootLayoutFrames, - frame => AssertFrame.Text(frame, "RootLayout starts here", sequence: 0), - frame => AssertFrame.Region(frame, subtreeLength: 3, sequence: 1), - frame => AssertFrame.Component(frame, subtreeLength: 2, sequence: 0), - frame => AssertFrame.Attribute(frame, nameof(LayoutComponentBase.Body), sequence: 1), - frame => AssertFrame.Text(frame, "RootLayout ends here", sequence: 2)); - - var nestedLayoutComponentId = batch.GetComponentFrames().Single().ComponentId; - var nestedLayoutFrames = _renderer.GetCurrentRenderTreeFrames(nestedLayoutComponentId).AsEnumerable(); - Assert.Collection(nestedLayoutFrames, - frame => AssertFrame.Text(frame, "NestedLayout starts here", sequence: 0), - frame => AssertFrame.Region(frame, subtreeLength: 3, sequence: 1), - frame => AssertFrame.Text(frame, "Hello", sequence: 123), - frame => AssertFrame.Text(frame, "Goodbye", sequence: 456), - frame => AssertFrame.Text(frame, "NestedLayout ends here", sequence: 2)); - } - - [Fact] - public void CanChangeContentWithSameLayout() - { - // Arrange - var setParametersTask = _renderer.Dispatcher.InvokeAsync(() => _layoutViewComponent.SetParametersAsync(ParameterView.FromDictionary(new Dictionary - { - { nameof(LayoutView.Layout), typeof(NestedLayout) }, - { nameof(LayoutView.ChildContent), (RenderFragment)(builder => { - builder.AddContent(0, "Initial content"); - })} - }))); - - // Act - Assert.True(setParametersTask.IsCompletedSuccessfully); - _renderer.Dispatcher.InvokeAsync(() => _layoutViewComponent.SetParametersAsync(ParameterView.FromDictionary(new Dictionary - { - { nameof(LayoutView.Layout), typeof(NestedLayout) }, - { nameof(LayoutView.ChildContent), (RenderFragment)(builder => { - builder.AddContent(0, "Changed content"); - })} - }))); - - // Assert - Assert.Equal(2, _renderer.Batches.Count); - var batch = _renderer.Batches[1]; - Assert.Equal(0, batch.DisposedComponentIDs.Count); - Assert.Collection(batch.DiffsInOrder, - diff => Assert.Empty(diff.Edits), // LayoutView rerendered, but with no changes - diff => Assert.Empty(diff.Edits), // RootLayout rerendered, but with no changes - diff => - { - // NestedLayout rerendered, patching content in place - Assert.Collection(diff.Edits, edit => - { - Assert.Equal(RenderTreeEditType.UpdateText, edit.Type); - Assert.Equal(1, edit.SiblingIndex); - AssertFrame.Text( - batch.ReferenceFrames[edit.ReferenceFrameIndex], - "Changed content", - sequence: 0); - }); - }); - } - - [Fact] - public void CanChangeLayout() - { - // Arrange - var setParametersTask1 = _renderer.Dispatcher.InvokeAsync(() => _layoutViewComponent.SetParametersAsync(ParameterView.FromDictionary(new Dictionary - { - { nameof(LayoutView.Layout), typeof(NestedLayout) }, - { nameof(LayoutView.ChildContent), (RenderFragment)(builder => { - builder.AddContent(0, "Some content"); - })} - }))); - Assert.True(setParametersTask1.IsCompletedSuccessfully); - - // Act - var setParametersTask2 = _renderer.Dispatcher.InvokeAsync(() => _layoutViewComponent.SetParametersAsync(ParameterView.FromDictionary(new Dictionary - { - { nameof(LayoutView.Layout), typeof(OtherNestedLayout) }, - }))); - - // Assert - Assert.True(setParametersTask2.IsCompletedSuccessfully); - Assert.Equal(2, _renderer.Batches.Count); - var batch = _renderer.Batches[1]; - Assert.Equal(1, batch.DisposedComponentIDs.Count); // Disposes NestedLayout - Assert.Collection(batch.DiffsInOrder, - diff => Assert.Empty(diff.Edits), // LayoutView rerendered, but with no changes - diff => - { - // RootLayout rerendered, changing child - Assert.Collection(diff.Edits, - edit => - { - Assert.Equal(RenderTreeEditType.RemoveFrame, edit.Type); - Assert.Equal(1, edit.SiblingIndex); - }, - edit => - { - Assert.Equal(RenderTreeEditType.PrependFrame, edit.Type); - Assert.Equal(1, edit.SiblingIndex); - AssertFrame.Component( - batch.ReferenceFrames[edit.ReferenceFrameIndex], - sequence: 0); - }); - }, - diff => - { - // Inserts new OtherNestedLayout - Assert.Collection(diff.Edits, - edit => - { - Assert.Equal(RenderTreeEditType.PrependFrame, edit.Type); - Assert.Equal(0, edit.SiblingIndex); - AssertFrame.Text( - batch.ReferenceFrames[edit.ReferenceFrameIndex], - "OtherNestedLayout starts here"); - }, - edit => - { - Assert.Equal(RenderTreeEditType.PrependFrame, edit.Type); - Assert.Equal(1, edit.SiblingIndex); - AssertFrame.Text( - batch.ReferenceFrames[edit.ReferenceFrameIndex], - "Some content"); - }, - edit => - { - Assert.Equal(RenderTreeEditType.PrependFrame, edit.Type); - Assert.Equal(2, edit.SiblingIndex); - AssertFrame.Text( - batch.ReferenceFrames[edit.ReferenceFrameIndex], - "OtherNestedLayout ends here"); - }); - }); - } - - private class RootLayout : AutoRenderComponent - { - [Parameter] - public RenderFragment Body { get; set; } - - protected override void BuildRenderTree(RenderTreeBuilder builder) - { - if (Body == null) - { - // Prove that we don't expect layouts to tolerate null values for Body - throw new InvalidOperationException("Got a null body when not expecting it"); - } - - builder.AddContent(0, "RootLayout starts here"); - builder.AddContent(1, Body); - builder.AddContent(2, "RootLayout ends here"); - } - } - - [Layout(typeof(RootLayout))] - private class NestedLayout : AutoRenderComponent - { - [Parameter] - public RenderFragment Body { get; set; } - - protected override void BuildRenderTree(RenderTreeBuilder builder) - { - builder.AddContent(0, "NestedLayout starts here"); - builder.AddContent(1, Body); - builder.AddContent(2, "NestedLayout ends here"); - } - } - - [Layout(typeof(RootLayout))] - private class OtherNestedLayout : AutoRenderComponent - { - [Parameter] - public RenderFragment Body { get; set; } - - protected override void BuildRenderTree(RenderTreeBuilder builder) - { - builder.AddContent(0, "OtherNestedLayout starts here"); - builder.AddContent(1, Body); - builder.AddContent(2, "OtherNestedLayout ends here"); - } - } - } -} diff --git a/src/Components/Components/test/Microsoft.AspNetCore.Components.Tests.csproj b/src/Components/Components/test/Microsoft.AspNetCore.Components.Tests.csproj deleted file mode 100644 index fd2a5406c1..0000000000 --- a/src/Components/Components/test/Microsoft.AspNetCore.Components.Tests.csproj +++ /dev/null @@ -1,18 +0,0 @@ - - - - $(DefaultNetCoreTargetFramework) - Microsoft.AspNetCore.Components - - - - - - - - - - - - - diff --git a/src/Components/Components/test/NavigationManagerTest.cs b/src/Components/Components/test/NavigationManagerTest.cs deleted file mode 100644 index 9b857bb044..0000000000 --- a/src/Components/Components/test/NavigationManagerTest.cs +++ /dev/null @@ -1,117 +0,0 @@ -// 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 Xunit; - -namespace Microsoft.AspNetCore.Components -{ - public class NavigationManagerTest - { - [Theory] - [InlineData("scheme://host/", "scheme://host/")] - [InlineData("scheme://host:123/", "scheme://host:123/")] - [InlineData("scheme://host/path", "scheme://host/")] - [InlineData("scheme://host/path/", "scheme://host/path/")] - [InlineData("scheme://host/path/page?query=string&another=here", "scheme://host/path/")] - public void ComputesCorrectBaseUri(string baseUri, string expectedResult) - { - var actualResult = NavigationManager.NormalizeBaseUri(baseUri); - Assert.Equal(expectedResult, actualResult); - } - - [Theory] - [InlineData("scheme://host/", "scheme://host", "")] - [InlineData("scheme://host/", "scheme://host/", "")] - [InlineData("scheme://host/", "scheme://host/path", "path")] - [InlineData("scheme://host/path/", "scheme://host/path/", "")] - [InlineData("scheme://host/path/", "scheme://host/path/more", "more")] - [InlineData("scheme://host/path/", "scheme://host/path", "")] - [InlineData("scheme://host/path/", "scheme://host/path#hash", "#hash")] - [InlineData("scheme://host/path/", "scheme://host/path/#hash", "#hash")] - [InlineData("scheme://host/path/", "scheme://host/path/more#hash", "more#hash")] - public void ComputesCorrectValidBaseRelativePaths(string baseUri, string uri, string expectedResult) - { - var navigationManager = new TestNavigationManager(baseUri); - - var actualResult = navigationManager.ToBaseRelativePath(uri); - Assert.Equal(expectedResult, actualResult); - } - - [Theory] - [InlineData("scheme://host/", "otherscheme://host/")] - [InlineData("scheme://host/", "scheme://otherhost/")] - [InlineData("scheme://host/path/", "scheme://host/")] - public void Initialize_ThrowsForInvalidBaseRelativePaths(string baseUri, string absoluteUri) - { - var navigationManager = new TestNavigationManager(); - - var ex = Assert.Throws(() => - { - navigationManager.Initialize(baseUri, absoluteUri); - }); - - Assert.Equal( - $"The URI '{absoluteUri}' is not contained by the base URI '{baseUri}'.", - ex.Message); - } - - [Theory] - [InlineData("scheme://host/", "otherscheme://host/")] - [InlineData("scheme://host/", "scheme://otherhost/")] - [InlineData("scheme://host/path/", "scheme://host/")] - public void Uri_ThrowsForInvalidBaseRelativePaths(string baseUri, string absoluteUri) - { - var navigationManager = new TestNavigationManager(baseUri); - - var ex = Assert.Throws(() => - { - navigationManager.ToBaseRelativePath(absoluteUri); - }); - - Assert.Equal( - $"The URI '{absoluteUri}' is not contained by the base URI '{baseUri}'.", - ex.Message); - } - - [Theory] - [InlineData("scheme://host/", "otherscheme://host/")] - [InlineData("scheme://host/", "scheme://otherhost/")] - [InlineData("scheme://host/path/", "scheme://host/")] - public void ToBaseRelativePath_ThrowsForInvalidBaseRelativePaths(string baseUri, string absoluteUri) - { - var navigationManager = new TestNavigationManager(baseUri); - - var ex = Assert.Throws(() => - { - navigationManager.ToBaseRelativePath(absoluteUri); - }); - - Assert.Equal( - $"The URI '{absoluteUri}' is not contained by the base URI '{baseUri}'.", - ex.Message); - } - - private class TestNavigationManager : NavigationManager - { - public TestNavigationManager() - { - } - - public TestNavigationManager(string baseUri = null, string uri = null) - { - Initialize(baseUri ?? "http://example.com/", uri ?? baseUri ?? "http://example.com/welcome-page"); - } - - public new void Initialize(string baseUri, string uri) - { - base.Initialize(baseUri, uri); - } - - protected override void NavigateToCore(string uri, bool forceLoad) - { - throw new System.NotImplementedException(); - } - } - } -} diff --git a/src/Components/Components/test/OwningComponentBaseTest.cs b/src/Components/Components/test/OwningComponentBaseTest.cs deleted file mode 100644 index 155231b40b..0000000000 --- a/src/Components/Components/test/OwningComponentBaseTest.cs +++ /dev/null @@ -1,61 +0,0 @@ -// 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.Dynamic; -using System.Linq; -using Microsoft.AspNetCore.Components.RenderTree; -using Microsoft.AspNetCore.Components.Test.Helpers; -using Microsoft.Extensions.DependencyInjection; -using Xunit; - -namespace Microsoft.AspNetCore.Components -{ - public class OwningComponentBaseTest - { - [Fact] - public void CreatesScopeAndService() - { - var services = new ServiceCollection(); - services.AddSingleton(); - services.AddTransient(); - var serviceProvider = services.BuildServiceProvider(); - - var counter = serviceProvider.GetRequiredService(); - var renderer = new TestRenderer(serviceProvider); - var component1 = renderer.InstantiateComponent(); - - Assert.NotNull(component1.MyService); - Assert.Equal(1, counter.CreatedCount); - Assert.Equal(0, counter.DisposedCount); - - ((IDisposable)component1).Dispose(); - Assert.Equal(1, counter.CreatedCount); - Assert.Equal(1, counter.DisposedCount); - } - - private class Counter - { - public int CreatedCount { get; set; } - public int DisposedCount { get; set; } - } - - private class MyService : IDisposable - { - public MyService(Counter counter) - { - Counter = counter; - Counter.CreatedCount++; - } - - public Counter Counter { get; } - - void IDisposable.Dispose() => Counter.DisposedCount++; - } - - private class MyOwningComponent : OwningComponentBase - { - public MyService MyService => Service; - } - } -} diff --git a/src/Components/Components/test/ParameterViewTest.Assignment.cs b/src/Components/Components/test/ParameterViewTest.Assignment.cs deleted file mode 100644 index 9df9feab9f..0000000000 --- a/src/Components/Components/test/ParameterViewTest.Assignment.cs +++ /dev/null @@ -1,718 +0,0 @@ -// 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.Collections; -using System.Collections.Generic; -using System.Linq; -using Microsoft.AspNetCore.Components.Rendering; -using Xunit; - -namespace Microsoft.AspNetCore.Components -{ - public partial class ParameterViewTest - { - [Fact] - public void IncomingParameterMatchesAnnotatedPrivateProperty_SetsValue() - { - // Arrange - var someObject = new object(); - var parameters = new ParameterViewBuilder - { - { nameof(HasInstanceProperties.IntProp), 123 }, - { nameof(HasInstanceProperties.StringProp), "Hello" }, - { HasInstanceProperties.ObjectPropName, someObject }, - }.Build(); - var target = new HasInstanceProperties(); - - // Act - parameters.SetParameterProperties(target); - - // Assert - Assert.Equal(123, target.IntProp); - Assert.Equal("Hello", target.StringProp); - Assert.Same(someObject, target.ObjectPropCurrentValue); - } - - [Fact] - public void IncomingParameterMatchesDeclaredParameterCaseInsensitively_SetsValue() - { - // Arrange - var parameters = new ParameterViewBuilder - { - { nameof(HasInstanceProperties.IntProp).ToLowerInvariant(), 123 } - }.Build(); - var target = new HasInstanceProperties(); - - // Act - parameters.SetParameterProperties(target); - - // Assert - Assert.Equal(123, target.IntProp); - } - - [Fact] - public void IncomingParameterMatchesInheritedDeclaredParameter_SetsValue() - { - // Arrange - var parameters = new ParameterViewBuilder - { - { nameof(HasInheritedProperties.IntProp), 123 }, - { nameof(HasInheritedProperties.DerivedClassIntProp), 456 }, - }.Build(); - var target = new HasInheritedProperties(); - - // Act - parameters.SetParameterProperties(target); - - // Assert - Assert.Equal(123, target.IntProp); - Assert.Equal(456, target.DerivedClassIntProp); - } - - [Fact] - public void IncomingParameterMatchesOverridenParameter_ThatDoesNotHasAttribute() - { - // Test for https://github.com/aspnet/AspNetCore/issues/13162 - // Arrange - var parameters = new ParameterViewBuilder - { - { nameof(DerivedType.VirtualProp), 123 }, - }.Build(); - var target = new DerivedType(); - - // Act - parameters.SetParameterProperties(target); - - // Assert - Assert.Equal(123, target.VirtualProp); - } - - [Fact] - public void NoIncomingParameterMatchesDeclaredParameter_LeavesValueUnchanged() - { - // Arrange - var existingObjectValue = new object(); - var target = new HasInstanceProperties - { - IntProp = 456, - StringProp = "Existing value", - ObjectPropCurrentValue = existingObjectValue - }; - - var parameters = new ParameterViewBuilder().Build(); - - // Act - parameters.SetParameterProperties(target); - - // Assert - Assert.Equal(456, target.IntProp); - Assert.Equal("Existing value", target.StringProp); - Assert.Same(existingObjectValue, target.ObjectPropCurrentValue); - } - - [Fact] - public void IncomingCascadingValueMatchesCascadingParameter_SetsValue() - { - // Arrange - var builder = new ParameterViewBuilder(); - builder.Add(nameof(HasCascadingParameter.Cascading), "hi", cascading: true); - var parameters = builder.Build(); - - var target = new HasCascadingParameter(); - - // Act - parameters.SetParameterProperties(target); - - // Assert - Assert.Equal("hi", target.Cascading); - } - - [Fact] - public void NoIncomingCascadingValueMatchesDeclaredCascadingParameter_LeavesValueUnchanged() - { - // Arrange - var builder = new ParameterViewBuilder(); - var parameters = builder.Build(); - - var target = new HasCascadingParameter() - { - Cascading = "bye", - }; - - // Act - parameters.SetParameterProperties(target); - - // Assert - Assert.Equal("bye", target.Cascading); - } - - [Fact] - public void IncomingCascadingValueMatchesNoDeclaredParameter_Throws() - { - // Arrange - var builder = new ParameterViewBuilder(); - builder.Add("SomethingElse", "hi", cascading: true); - var parameters = builder.Build(); - - var target = new HasCascadingParameter(); - - // Act - var ex = Assert.Throws(() => parameters.SetParameterProperties(target)); - - // Assert - Assert.Equal( - $"Object of type '{typeof(HasCascadingParameter).FullName}' does not have a property " + - $"matching the name 'SomethingElse'.", - ex.Message); - } - - [Fact] - public void IncomingParameterMatchesPropertyNotDeclaredAsParameter_Throws() - { - // Arrange - var target = new HasPropertyWithoutParameterAttribute(); - var parameters = new ParameterViewBuilder - { - { nameof(HasPropertyWithoutParameterAttribute.IntProp), 123 }, - }.Build(); - - // Act - var ex = Assert.Throws( - () => parameters.SetParameterProperties(target)); - - // Assert - Assert.Equal(default, target.IntProp); - Assert.Equal( - $"Object of type '{typeof(HasPropertyWithoutParameterAttribute).FullName}' has a property matching the name '{nameof(HasPropertyWithoutParameterAttribute.IntProp)}', " + - $"but it does not have [{nameof(ParameterAttribute)}] or [{nameof(CascadingParameterAttribute)}] applied.", - ex.Message); - } - - [Fact] - public void IncomingParameterMatchesPropertyNotPublic_Throws() - { - // Arrange - var target = new HasNonPublicPropertyWithParameterAttribute(); - var parameters = new ParameterViewBuilder - { - { nameof(HasNonPublicPropertyWithParameterAttribute.IntProp), 123 }, - }.Build(); - - // Act - var ex = Assert.Throws( - () => parameters.SetParameterProperties(target)); - - // Assert - Assert.Equal(default, target.IntProp); - Assert.Equal( - $"The type '{typeof(HasNonPublicPropertyWithParameterAttribute).FullName}' declares a parameter matching the name '{nameof(HasNonPublicPropertyWithParameterAttribute.IntProp)}' that is not public. Parameters must be public.", - ex.Message); - } - - [Fact] - public void IncomingCascadingParameterMatchesPropertyNotPublic_Works() - { - // Arrange - var target = new HasNonPublicCascadingParameter(); - var builder = new ParameterViewBuilder(); - builder.Add("Cascading", "Test", cascading: true); - var parameters = builder.Build(); - - // Act - parameters.SetParameterProperties(target); - - // Assert - Assert.Equal("Test", target.GetCascadingValue()); - } - - [Fact] - public void IncomingNonCascadingValueMatchesCascadingParameter_Throws() - { - // Arrange - var target = new HasCascadingParameter(); - var parameters = new ParameterViewBuilder - { - { nameof(HasCascadingParameter.Cascading), 123 }, - }.Build(); - - // Act - var ex = Assert.Throws(() => parameters.SetParameterProperties(target)); - - // Assert - Assert.Equal( - $"Object of type '{typeof(HasCascadingParameter).FullName}' has a property matching the name '{nameof(HasCascadingParameter.Cascading)}', " + - $"but it does not have [{nameof(ParameterAttribute)}] applied.", - ex.Message); - } - - [Fact] - public void IncomingCascadingValueMatchesNonCascadingParameter_Throws() - { - // Arrange - var target = new HasInstanceProperties(); - var builder = new ParameterViewBuilder(); - builder.Add(nameof(HasInstanceProperties.IntProp), 16, cascading: true); - var parameters = builder.Build(); - - // Act - var ex = Assert.Throws(() => parameters.SetParameterProperties(target)); - - // Assert - Assert.Equal( - $"The property '{nameof(HasInstanceProperties.IntProp)}' on component type '{typeof(HasInstanceProperties).FullName}' " + - $"cannot be set using a cascading value.", - ex.Message); - } - - [Fact] - public void SettingCaptureUnmatchedValuesParameterExplicitlyWorks() - { - // Arrange - var target = new HasCaptureUnmatchedValuesProperty(); - var value = new Dictionary(); - var parameters = new ParameterViewBuilder - { - { nameof(HasCaptureUnmatchedValuesProperty.CaptureUnmatchedValues), value }, - }.Build(); - - // Act - parameters.SetParameterProperties(target); - - // Assert - Assert.Same(value, target.CaptureUnmatchedValues); - } - - [Fact] - public void SettingCaptureUnmatchedValuesParameterWithUnmatchedValuesWorks() - { - // Arrange - var target = new HasCaptureUnmatchedValuesProperty(); - var parameters = new ParameterViewBuilder - { - { nameof(HasCaptureUnmatchedValuesProperty.StringProp), "hi" }, - { "test1", 123 }, - { "test2", 456 }, - }.Build(); - - // Act - parameters.SetParameterProperties(target); - - // Assert - Assert.Equal("hi", target.StringProp); - Assert.Collection( - target.CaptureUnmatchedValues.OrderBy(kvp => kvp.Key), - kvp => - { - Assert.Equal("test1", kvp.Key); - Assert.Equal(123, kvp.Value); - }, - kvp => - { - Assert.Equal("test2", kvp.Key); - Assert.Equal(456, kvp.Value); - }); - } - - [Fact] - public void SettingCaptureUnmatchedValuesParameterExplicitlyAndImplicitly_Throws() - { - // Arrange - var target = new HasCaptureUnmatchedValuesProperty(); - var parameters = new ParameterViewBuilder - { - { nameof(HasCaptureUnmatchedValuesProperty.CaptureUnmatchedValues), new Dictionary() }, - { "test1", 123 }, - { "test2", 456 }, - }.Build(); - - // Act - var ex = Assert.Throws(() => parameters.SetParameterProperties(target)); - - // Assert - Assert.Equal( - $"The property '{nameof(HasCaptureUnmatchedValuesProperty.CaptureUnmatchedValues)}' on component type '{typeof(HasCaptureUnmatchedValuesProperty).FullName}' cannot be set explicitly when " + - $"also used to capture unmatched values. Unmatched values:" + Environment.NewLine + - $"test1" + Environment.NewLine + - $"test2", - ex.Message); - } - - [Fact] - public void SettingCaptureUnmatchedValuesParameterExplicitlyAndImplicitly_ReverseOrder_Throws() - { - // Arrange - var target = new HasCaptureUnmatchedValuesProperty(); - var parameters = new ParameterViewBuilder - { - { "test2", 456 }, - { "test1", 123 }, - { nameof(HasCaptureUnmatchedValuesProperty.CaptureUnmatchedValues), new Dictionary() }, - }.Build(); - - // Act - var ex = Assert.Throws(() => parameters.SetParameterProperties(target)); - - // Assert - Assert.Equal( - $"The property '{nameof(HasCaptureUnmatchedValuesProperty.CaptureUnmatchedValues)}' on component type '{typeof(HasCaptureUnmatchedValuesProperty).FullName}' cannot be set explicitly when " + - $"also used to capture unmatched values. Unmatched values:" + Environment.NewLine + - $"test1" + Environment.NewLine + - $"test2", - ex.Message); - } - - [Fact] - public void HasDuplicateCaptureUnmatchedValuesParameters_Throws() - { - // Arrange - var target = new HasDupliateCaptureUnmatchedValuesProperty(); - var parameters = new ParameterViewBuilder().Build(); - - // Act - var ex = Assert.Throws(() => parameters.SetParameterProperties(target)); - - // Assert - Assert.Equal( - $"Multiple properties were found on component type '{typeof(HasDupliateCaptureUnmatchedValuesProperty).FullName}' " + - $"with '{nameof(ParameterAttribute)}.{nameof(ParameterAttribute.CaptureUnmatchedValues)}'. " + - $"Only a single property per type can use '{nameof(ParameterAttribute)}.{nameof(ParameterAttribute.CaptureUnmatchedValues)}'. " + - $"Properties:" + Environment.NewLine + - $"{nameof(HasDupliateCaptureUnmatchedValuesProperty.CaptureUnmatchedValuesProp1)}" + Environment.NewLine + - $"{nameof(HasDupliateCaptureUnmatchedValuesProperty.CaptureUnmatchedValuesProp2)}", - ex.Message); - } - - [Fact] - public void HasCaptureUnmatchedValuesParameteterWithWrongType_Throws() - { - // Arrange - var target = new HasWrongTypeCaptureUnmatchedValuesProperty(); - var parameters = new ParameterViewBuilder().Build(); - - // Act - var ex = Assert.Throws(() => parameters.SetParameterProperties(target)); - - // Assert - Assert.Equal( - $"The property '{nameof(HasWrongTypeCaptureUnmatchedValuesProperty.CaptureUnmatchedValuesProp)}' on component type '{typeof(HasWrongTypeCaptureUnmatchedValuesProperty).FullName}' cannot be used with " + - $"'{nameof(ParameterAttribute)}.{nameof(ParameterAttribute.CaptureUnmatchedValues)}' because it has the wrong type. " + - $"The property must be assignable from 'Dictionary'.", - ex.Message); - } - - [Fact] - public void IncomingNonCascadingValueMatchesCascadingParameter_WithCaptureUnmatchedValues_DoesNotThrow() - { - // Arrange - var target = new HasCaptureUnmatchedValuesPropertyAndCascadingParameter() - { - Cascading = "bye", - }; - var parameters = new ParameterViewBuilder - { - { nameof(HasCaptureUnmatchedValuesPropertyAndCascadingParameter.Cascading), "hi" }, - }.Build(); - - // Act - parameters.SetParameterProperties(target); - - Assert.Collection( - target.CaptureUnmatchedValues, - kvp => - { - Assert.Equal(nameof(HasCaptureUnmatchedValuesPropertyAndCascadingParameter.Cascading), kvp.Key); - Assert.Equal("hi", kvp.Value); - }); - Assert.Equal("bye", target.Cascading); - } - - [Fact] - public void IncomingCascadingValueMatchesNonCascadingParameter_WithCaptureUnmatchedValues_Throws() - { - // Arrange - var target = new HasCaptureUnmatchedValuesProperty(); - var builder = new ParameterViewBuilder(); - builder.Add(nameof(HasInstanceProperties.IntProp), 16, cascading: true); - var parameters = builder.Build(); - - // Act - var ex = Assert.Throws(() => parameters.SetParameterProperties(target)); - - // Assert - Assert.Equal( - $"The property '{nameof(HasCaptureUnmatchedValuesProperty.IntProp)}' on component type '{typeof(HasCaptureUnmatchedValuesProperty).FullName}' " + - $"cannot be set using a cascading value.", - ex.Message); - } - - [Fact] - public void IncomingParameterValueMismatchesDeclaredParameterType_Throws() - { - // Arrange - var someObject = new object(); - var parameters = new ParameterViewBuilder - { - { nameof(HasInstanceProperties.IntProp), "string value" }, - }.Build(); - var target = new HasInstanceProperties(); - - // Act - var ex = Assert.Throws( - () => parameters.SetParameterProperties(target)); - - // Assert - Assert.Equal( - $"Unable to set property '{nameof(HasInstanceProperties.IntProp)}' on object of " + - $"type '{typeof(HasInstanceProperties).FullName}'. The error was: {ex.InnerException.Message}", - ex.Message); - } - - [Fact] - public void PropertyExplicitSetterException_Throws() - { - // Arrange - var target = new HasPropertyWhoseSetterThrows(); - var parameters = new ParameterViewBuilder - { - { nameof(HasPropertyWhoseSetterThrows.StringProp), "anything" }, - }.Build(); - - // Act - var ex = Assert.Throws( - () => parameters.SetParameterProperties(target)); - - // Assert - Assert.Equal( - $"Unable to set property '{nameof(HasPropertyWhoseSetterThrows.StringProp)}' on object of " + - $"type '{typeof(HasPropertyWhoseSetterThrows).FullName}'. The error was: {ex.InnerException.Message}", - ex.Message); - } - - [Fact] - public void DeclaredParametersVaryOnlyByCase_Throws() - { - // Arrange - var parameters = new ParameterViewBuilder().Build(); - var target = new HasParametersVaryingOnlyByCase(); - - // Act - var ex = Assert.Throws(() => - parameters.SetParameterProperties(target)); - - // Assert - Assert.Equal( - $"The type '{typeof(HasParametersVaryingOnlyByCase).FullName}' declares more than one parameter matching the " + - $"name '{nameof(HasParametersVaryingOnlyByCase.MyValue).ToLowerInvariant()}'. Parameter names are case-insensitive and must be unique.", - ex.Message); - } - - [Fact] - public void DeclaredParameterClashesWithInheritedParameter_Throws() - { - // Even when the developer uses 'new' to shadow an inherited property, this is not - // an allowed scenario because there would be no way for the consumer to specify - // both property values, and it's no good leaving the shadowed one unset because the - // base class can legitimately depend on it for correct functioning. - - // Arrange - var parameters = new ParameterViewBuilder().Build(); - var target = new HasParameterClashingWithInherited(); - - // Act - var ex = Assert.Throws(() => - parameters.SetParameterProperties(target)); - - // Assert - Assert.Equal( - $"The type '{typeof(HasParameterClashingWithInherited).FullName}' declares more than one parameter matching the " + - $"name '{nameof(HasParameterClashingWithInherited.IntProp).ToLowerInvariant()}'. Parameter names are case-insensitive and must be unique.", - ex.Message); - } - - [Fact] - public void SupplyingNullWritesDefaultForType() - { - // Arrange - var parameters = new ParameterViewBuilder - { - { nameof(HasInstanceProperties.IntProp), null }, - { nameof(HasInstanceProperties.StringProp), null }, - }.Build(); - var target = new HasInstanceProperties { IntProp = 123, StringProp = "Hello" }; - - // Act - parameters.SetParameterProperties(target); - - // Assert - Assert.Equal(0, target.IntProp); - Assert.Null(target.StringProp); - } - - class HasInstanceProperties - { - [Parameter] public int IntProp { get; set; } - [Parameter] public string StringProp { get; set; } - - [Parameter] public object ObjectProp { get; set; } - - public static string ObjectPropName => nameof(ObjectProp); - public object ObjectPropCurrentValue - { - get => ObjectProp; - set => ObjectProp = value; - } - } - - class HasCascadingParameter - { - [CascadingParameter] public string Cascading { get; set; } - } - - class HasPropertyWithoutParameterAttribute - { - public int IntProp { get; set; } - } - - class HasNonPublicPropertyWithParameterAttribute - { - [Parameter] - internal int IntProp { get; set; } - } - - class HasPropertyWhoseSetterThrows - { - [Parameter] - public string StringProp - { - get => string.Empty; - set => throw new InvalidOperationException("This setter throws"); - } - } - - class HasInheritedProperties : HasInstanceProperties - { - [Parameter] public int DerivedClassIntProp { get; set; } - } - - class BaseType - { - [Parameter] public virtual int VirtualProp { get; set; } - } - - class DerivedType : BaseType - { - public override int VirtualProp { get; set; } - } - - class HasParametersVaryingOnlyByCase - { - [Parameter] public object MyValue { get; set; } - [Parameter] public object Myvalue { get; set; } - } - - class HasParameterClashingWithInherited : HasInstanceProperties - { - [Parameter] public new int IntProp { get; set; } - } - - class HasCaptureUnmatchedValuesProperty - { - [Parameter] public int IntProp { get; set; } - [Parameter] public string StringProp { get; set; } - [Parameter] public object ObjectProp { get; set; } - [Parameter(CaptureUnmatchedValues = true)] public IReadOnlyDictionary CaptureUnmatchedValues { get; set; } - } - - class HasCaptureUnmatchedValuesPropertyAndCascadingParameter - { - [CascadingParameter] public string Cascading { get; set; } - [Parameter(CaptureUnmatchedValues = true)] public IReadOnlyDictionary CaptureUnmatchedValues { get; set; } - } - - class HasDupliateCaptureUnmatchedValuesProperty - { - [Parameter(CaptureUnmatchedValues = true)] public Dictionary CaptureUnmatchedValuesProp1 { get; set; } - [Parameter(CaptureUnmatchedValues = true)] public IDictionary CaptureUnmatchedValuesProp2 { get; set; } - } - - class HasWrongTypeCaptureUnmatchedValuesProperty - { - [Parameter(CaptureUnmatchedValues = true)] public KeyValuePair[] CaptureUnmatchedValuesProp { get; set; } - } - - class HasNonPublicCascadingParameter - { - [CascadingParameter] private string Cascading { get; set; } - - public string GetCascadingValue() => Cascading; - } - - class ParameterViewBuilder : IEnumerable - { - private readonly List<(string Name, object Value, bool Cascading)> _keyValuePairs - = new List<(string, object, bool)>(); - - public void Add(string name, object value, bool cascading = false) - => _keyValuePairs.Add((name, value, cascading)); - - public IEnumerator GetEnumerator() - => throw new NotImplementedException(); - - public ParameterView Build() - { - var builder = new RenderTreeBuilder(); - - builder.OpenComponent(0); - foreach (var kvp in _keyValuePairs) - { - if (!kvp.Cascading) - { - builder.AddAttribute(1, kvp.Name, kvp.Value); - } - } - builder.CloseComponent(); - - var view = new ParameterView(ParameterViewLifetime.Unbound, builder.GetFrames().Array, ownerIndex: 0); - - var cascadingParameters = new List(); - foreach (var kvp in _keyValuePairs) - { - if (kvp.Cascading) - { - cascadingParameters.Add(new CascadingParameterState(kvp.Name, new TestCascadingValueProvider(kvp.Value))); - } - } - - return view.WithCascadingParameters(cascadingParameters); - } - } - - private class TestCascadingValueProvider : ICascadingValueComponent - { - public TestCascadingValueProvider(object value) - { - CurrentValue = value; - } - - public object CurrentValue { get; } - - public bool CurrentValueIsFixed => throw new NotImplementedException(); - - public bool CanSupplyValue(Type valueType, string valueName) - { - throw new NotImplementedException(); - } - - public void Subscribe(ComponentState subscriber) - { - throw new NotImplementedException(); - } - - public void Unsubscribe(ComponentState subscriber) - { - throw new NotImplementedException(); - } - } - } -} diff --git a/src/Components/Components/test/ParameterViewTest.cs b/src/Components/Components/test/ParameterViewTest.cs deleted file mode 100644 index 5193e8fe29..0000000000 --- a/src/Components/Components/test/ParameterViewTest.cs +++ /dev/null @@ -1,399 +0,0 @@ -// 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.Collections.Generic; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Components.Rendering; -using Microsoft.AspNetCore.Components.RenderTree; -using Xunit; - -namespace Microsoft.AspNetCore.Components -{ - public partial class ParameterViewTest - { - [Fact] - public void CanInitializeUsingComponentWithNoDescendants() - { - // Arrange - var frames = new[] - { - RenderTreeFrame.ChildComponent(0, typeof(FakeComponent)).WithComponentSubtreeLength(1) - }; - var parameters = new ParameterView(ParameterViewLifetime.Unbound, frames, 0); - - // Assert - Assert.Empty(ToEnumerable(parameters)); - } - - [Fact] - public void CanInitializeUsingElementWithNoDescendants() - { - // Arrange - var frames = new[] - { - RenderTreeFrame.Element(0, "some element").WithElementSubtreeLength(1) - }; - var parameters = new ParameterView(ParameterViewLifetime.Unbound, frames, 0); - - // Assert - Assert.Empty(ToEnumerable(parameters)); - } - - [Fact] - public void EnumerationStopsAtEndOfOwnerDescendants() - { - // Arrange - var attribute1Value = new object(); - var attribute2Value = new object(); - var frames = new[] - { - RenderTreeFrame.Element(0, "some element").WithElementSubtreeLength(3), - RenderTreeFrame.Attribute(1, "attribute 1", attribute1Value), - RenderTreeFrame.Attribute(2, "attribute 2", attribute2Value), - // Although RenderTreeBuilder doesn't let you add orphaned attributes like this, - // still want to verify that parameters doesn't attempt to read past the - // end of the owner's descendants - RenderTreeFrame.Attribute(3, "orphaned attribute", "value") - }; - var parameters = new ParameterView(ParameterViewLifetime.Unbound, frames, 0); - - // Assert - Assert.Collection(ToEnumerable(parameters), - AssertParameter("attribute 1", attribute1Value, false), - AssertParameter("attribute 2", attribute2Value, false)); - } - - [Fact] - public void EnumerationStopsAtEndOfOwnerAttributes() - { - // Arrange - var attribute1Value = new object(); - var attribute2Value = new object(); - var frames = new[] - { - RenderTreeFrame.Element(0, "some element").WithElementSubtreeLength(3), - RenderTreeFrame.Attribute(1, "attribute 1", attribute1Value), - RenderTreeFrame.Attribute(2, "attribute 2", attribute2Value), - RenderTreeFrame.Element(3, "child element").WithElementSubtreeLength(2), - RenderTreeFrame.Attribute(4, "child attribute", "some value") - }; - var parameters = new ParameterView(ParameterViewLifetime.Unbound, frames, 0); - - // Assert - Assert.Collection(ToEnumerable(parameters), - AssertParameter("attribute 1", attribute1Value, false), - AssertParameter("attribute 2", attribute2Value, false)); - } - - [Fact] - public void EnumerationIncludesCascadingParameters() - { - // Arrange - var attribute1Value = new object(); - var attribute2Value = new object(); - var attribute3Value = new object(); - var parameters = new ParameterView(ParameterViewLifetime.Unbound, new[] - { - RenderTreeFrame.Element(0, "some element").WithElementSubtreeLength(2), - RenderTreeFrame.Attribute(1, "attribute 1", attribute1Value) - }, 0).WithCascadingParameters(new List - { - new CascadingParameterState("attribute 2", new TestCascadingValue(attribute2Value)), - new CascadingParameterState("attribute 3", new TestCascadingValue(attribute3Value)), - }); - - // Assert - Assert.Collection(ToEnumerable(parameters), - AssertParameter("attribute 1", attribute1Value, false), - AssertParameter("attribute 2", attribute2Value, true), - AssertParameter("attribute 3", attribute3Value, true)); - } - - [Fact] - public void CanTryGetNonExistingValue() - { - // Arrange - var parameters = new ParameterView(ParameterViewLifetime.Unbound, new[] - { - RenderTreeFrame.Element(0, "some element").WithElementSubtreeLength(2), - RenderTreeFrame.Attribute(1, "some other entry", new object()) - }, 0); - - // Act - var didFind = parameters.TryGetValue("nonexisting entry", out var value); - - // Assert - Assert.False(didFind); - Assert.Null(value); - } - - [Fact] - public void CanTryGetExistingValueWithCorrectType() - { - // Arrange - var parameters = new ParameterView(ParameterViewLifetime.Unbound, new[] - { - RenderTreeFrame.Element(0, "some element").WithElementSubtreeLength(2), - RenderTreeFrame.Attribute(1, "my entry", "hello") - }, 0); - - // Act - var didFind = parameters.TryGetValue("my entry", out var value); - - // Assert - Assert.True(didFind); - Assert.Equal("hello", value); - } - - [Fact] - public void CanGetValueOrDefault_WithExistingValue() - { - // Arrange - var myEntryValue = new object(); - var parameters = new ParameterView(ParameterViewLifetime.Unbound, new[] - { - RenderTreeFrame.Element(0, "some element").WithElementSubtreeLength(2), - RenderTreeFrame.Attribute(1, "my entry", myEntryValue), - RenderTreeFrame.Attribute(1, "my other entry", new object()) - }, 0); - - // Act - var result = parameters.GetValueOrDefault("my entry"); - - // Assert - Assert.Same(myEntryValue, result); - } - - [Fact] - public void CanGetValueOrDefault_WithMultipleMatchingValues() - { - // Arrange - var myEntryValue = new object(); - var parameters = new ParameterView(ParameterViewLifetime.Unbound, new[] - { - RenderTreeFrame.Element(0, "some element").WithElementSubtreeLength(3), - RenderTreeFrame.Attribute(1, "my entry", myEntryValue), - RenderTreeFrame.Attribute(1, "my entry", new object()), - }, 0); - - // Act - var result = parameters.GetValueOrDefault("my entry"); - - // Assert: Picks first match - Assert.Same(myEntryValue, result); - } - - [Fact] - public void CanGetValueOrDefault_WithNonExistingValue() - { - // Arrange - var parameters = new ParameterView(ParameterViewLifetime.Unbound, new[] - { - RenderTreeFrame.Element(0, "some element").WithElementSubtreeLength(2), - RenderTreeFrame.Attribute(1, "some other entry", new object()) - }, 0).WithCascadingParameters(new List - { - new CascadingParameterState("another entry", new TestCascadingValue(null)) - }); - - // Act - var result = parameters.GetValueOrDefault("nonexisting entry"); - - // Assert - Assert.Equal(default, result); - } - - [Fact] - public void CanGetValueOrDefault_WithNonExistingValueAndExplicitDefault() - { - // Arrange - var explicitDefaultValue = new DateTime(2018, 3, 20); - var parameters = new ParameterView(ParameterViewLifetime.Unbound, new[] - { - RenderTreeFrame.Element(0, "some element").WithElementSubtreeLength(2), - RenderTreeFrame.Attribute(1, "some other entry", new object()) - }, 0); - - // Act - var result = parameters.GetValueOrDefault("nonexisting entry", explicitDefaultValue); - - // Assert - Assert.Equal(explicitDefaultValue, result); - } - - [Fact] - public void ThrowsIfTryGetExistingValueWithIncorrectType() - { - // Arrange - var parameters = new ParameterView(ParameterViewLifetime.Unbound, new[] - { - RenderTreeFrame.Element(0, "some element").WithElementSubtreeLength(2), - RenderTreeFrame.Attribute(1, "my entry", "hello") - }, 0); - - // Act/Assert - Assert.Throws(() => - { - parameters.TryGetValue("my entry", out var value); - }); - } - - [Fact] - public void FromDictionary_CanBeInitializedWithEmptyDictionary() - { - // Arrange - var dictionary = new Dictionary(); - - // Act - var collection = ParameterView.FromDictionary(dictionary); - - // Assert - Assert.Empty(collection.ToDictionary()); - } - - [Fact] - public void FromDictionary_RoundTrips() - { - // Arrange - var dictionary = new Dictionary - { - ["IntValue"] = 1, - ["StringValue"] = "String" - }; - - // Act - var collection = ParameterView.FromDictionary(dictionary); - - // Assert - Assert.Equal(dictionary, collection.ToDictionary()); - } - - - [Fact] - public void CanConvertToReadOnlyDictionary() - { - // Arrange - var entry2Value = new object(); - var parameters = new ParameterView(ParameterViewLifetime.Unbound, new[] - { - RenderTreeFrame.Element(0, "some element").WithElementSubtreeLength(3), - RenderTreeFrame.Attribute(0, "entry 1", "value 1"), - RenderTreeFrame.Attribute(0, "entry 2", entry2Value), - }, 0); - - // Act - IReadOnlyDictionary dict = parameters.ToDictionary(); - - // Assert - Assert.Collection(dict, - entry => - { - Assert.Equal("entry 1", entry.Key); - Assert.Equal("value 1", entry.Value); - }, - entry => - { - Assert.Equal("entry 2", entry.Key); - Assert.Same(entry2Value, entry.Value); - }); - } - - [Fact] - public void CanGetValueOrDefault_WithMatchingCascadingParameter() - { - // Arrange - var myEntryValue = new object(); - var parameters = new ParameterView(ParameterViewLifetime.Unbound, new[] - { - RenderTreeFrame.Element(0, "some element").WithElementSubtreeLength(2), - RenderTreeFrame.Attribute(1, "unrelated value", new object()) - }, 0).WithCascadingParameters(new List - { - new CascadingParameterState("unrelated value 2", new TestCascadingValue(null)), - new CascadingParameterState("my entry", new TestCascadingValue(myEntryValue)), - new CascadingParameterState("unrelated value 3", new TestCascadingValue(null)), - }); - - // Act - var result = parameters.GetValueOrDefault("my entry"); - - // Assert - Assert.Same(myEntryValue, result); - } - - [Fact] - public void CannotReadAfterLifetimeExpiry() - { - // Arrange - var builder = new RenderBatchBuilder(); - var lifetime = new ParameterViewLifetime(builder); - var frames = new[] - { - RenderTreeFrame.ChildComponent(0, typeof(FakeComponent)).WithComponentSubtreeLength(1) - }; - var parameterView = new ParameterView(lifetime, frames, 0); - - // Act - builder.InvalidateParameterViews(); - - // Assert - Assert.Throws(() => parameterView.GetEnumerator()); - Assert.Throws(() => parameterView.GetValueOrDefault("anything")); - Assert.Throws(() => parameterView.SetParameterProperties(new object())); - Assert.Throws(() => parameterView.ToDictionary()); - var ex = Assert.Throws(() => parameterView.TryGetValue("anything", out _)); - - // It's enough to assert about one of the messages - Assert.Equal($"The {nameof(ParameterView)} instance can no longer be read because it has expired. {nameof(ParameterView)} can only be read synchronously and must not be stored for later use.", ex.Message); - } - - private Action AssertParameter(string expectedName, object expectedValue, bool expectedIsCascading) - { - return parameter => - { - Assert.Equal(expectedName, parameter.Name); - Assert.Same(expectedValue, parameter.Value); - Assert.Equal(expectedIsCascading, parameter.Cascading); - }; - } - - public IEnumerable ToEnumerable(ParameterView parameters) - { - foreach (var item in parameters) - { - yield return item; - } - } - - private class FakeComponent : IComponent - { - public void Attach(RenderHandle renderHandle) - => throw new NotImplementedException(); - - public Task SetParametersAsync(ParameterView parameters) - => throw new NotImplementedException(); - } - - private class TestCascadingValue : ICascadingValueComponent - { - public TestCascadingValue(object value) - { - CurrentValue = value; - } - - public object CurrentValue { get; } - - public bool CurrentValueIsFixed => false; - - public bool CanSupplyValue(Type valueType, string valueName) - => throw new NotImplementedException(); - - public void Subscribe(ComponentState subscriber) - => throw new NotImplementedException(); - - public void Unsubscribe(ComponentState subscriber) - => throw new NotImplementedException(); - } - } -} diff --git a/src/Components/Components/test/RenderTreeDiffBuilderTest.cs b/src/Components/Components/test/RenderTreeDiffBuilderTest.cs deleted file mode 100644 index 28f617eba2..0000000000 --- a/src/Components/Components/test/RenderTreeDiffBuilderTest.cs +++ /dev/null @@ -1,2309 +0,0 @@ -// 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.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Components.Rendering; -using Microsoft.AspNetCore.Components.RenderTree; -using Microsoft.AspNetCore.Components.Test.Helpers; -using Microsoft.Extensions.Logging.Abstractions; -using Xunit; - -namespace Microsoft.AspNetCore.Components.Test -{ - public class RenderTreeDiffBuilderTest : IDisposable - { - private readonly Renderer renderer; - private readonly RenderTreeBuilder oldTree; - private readonly RenderTreeBuilder newTree; - private RenderBatchBuilder batchBuilder; - - public RenderTreeDiffBuilderTest() - { - renderer = new FakeRenderer(); - oldTree = new RenderTreeBuilder(); - newTree = new RenderTreeBuilder(); - } - - void IDisposable.Dispose() - { - renderer.Dispose(); - ((IDisposable)oldTree).Dispose(); - ((IDisposable)newTree).Dispose(); - batchBuilder?.Dispose(); - } - - [Theory] - [MemberData(nameof(RecognizesEquivalentFramesAsSameCases))] - public void RecognizesEquivalentFramesAsSame(RenderFragment appendFragment) - { - // Arrange - appendFragment(oldTree); - appendFragment(newTree); - - // Act - var (result, referenceFrames) = GetSingleUpdatedComponent(initializeFromFrames: true); - - // Assert - Assert.Empty(result.Edits); - } - - public static IEnumerable RecognizesEquivalentFramesAsSameCases() - => new RenderFragment[] - { - builder => builder.AddContent(0, "Hello"), - builder => - { - builder.OpenElement(0, "Some Element"); - builder.CloseElement(); - }, - builder => - { - builder.OpenElement(0, "Some Element"); - builder.AddAttribute(1, "My attribute", "My value"); - builder.CloseElement(); - }, - builder => - { - builder.OpenComponent(0); - builder.CloseComponent(); - } - }.Select(x => new object[] { x }); - - [Fact] - public void RecognizesNewItemsBeingInserted() - { - // Arrange - oldTree.AddContent(0, "text0"); - oldTree.AddContent(2, "text2"); - newTree.AddContent(0, "text0"); - newTree.AddContent(1, "text1"); - newTree.AddContent(2, "text2"); - - // Act - var (result, referenceFrames) = GetSingleUpdatedComponent(); - - // Assert - Assert.Collection(result.Edits, - entry => - { - AssertEdit(entry, RenderTreeEditType.PrependFrame, 1); - Assert.Equal(0, entry.ReferenceFrameIndex); - AssertFrame.Text(referenceFrames[0], "text1", 1); - }); - } - - [Fact] - public void RecognizesOldItemsBeingRemoved() - { - // Arrange - oldTree.AddContent(0, "text0"); - oldTree.AddContent(1, "text1"); - oldTree.AddContent(2, "text2"); - newTree.AddContent(0, "text0"); - newTree.AddContent(2, "text2"); - - // Act - var (result, referenceFrames) = GetSingleUpdatedComponent(); - - // Assert - Assert.Collection(result.Edits, - entry => AssertEdit(entry, RenderTreeEditType.RemoveFrame, 1)); - } - - [Fact] - public void RecognizesKeyedElementInsertions() - { - // Arrange - oldTree.OpenElement(0, "container"); - oldTree.SetKey("retained key"); - oldTree.AddContent(1, "Existing"); - oldTree.CloseElement(); - - newTree.OpenElement(0, "container"); - newTree.SetKey("new key"); - newTree.AddContent(1, "Inserted"); - newTree.CloseElement(); - - newTree.OpenElement(0, "container"); - newTree.SetKey("retained key"); - newTree.AddContent(1, "Existing"); - newTree.CloseElement(); - - // Without the key, it would change the text "Existing" to "Inserted", then insert a new "Existing" below it - // With the key, it just inserts a new "Inserted" at the top - - // Act - var (result, referenceFrames) = GetSingleUpdatedComponent(); - - // Assert - Assert.Collection(result.Edits, - entry => - { - AssertEdit(entry, RenderTreeEditType.PrependFrame, 0); - Assert.Equal(0, entry.ReferenceFrameIndex); - Assert.Equal("new key", referenceFrames[entry.ReferenceFrameIndex].ElementKey); - }); - } - - [Fact] - public void RecognizesKeyedElementDeletions() - { - // Arrange - oldTree.OpenElement(0, "container"); - oldTree.SetKey("will delete"); - oldTree.AddContent(1, "First"); - oldTree.CloseElement(); - - oldTree.OpenElement(0, "container"); - oldTree.SetKey("will retain"); - oldTree.AddContent(1, "Second"); - oldTree.CloseElement(); - - newTree.OpenElement(0, "container"); - newTree.SetKey("will retain"); - newTree.AddContent(1, "Second"); - newTree.CloseElement(); - - // Without the key, it changes the text content of "First" to "Second", then deletes the other "Second" - // With the key, it just deletes "First" - - // Act - var (result, referenceFrames) = GetSingleUpdatedComponent(); - - // Assert - Assert.Collection(result.Edits, - entry => AssertEdit(entry, RenderTreeEditType.RemoveFrame, 0)); - } - - [Fact] - public void RecognizesSimultaneousKeyedElementInsertionsAndDeletions() - { - // Arrange - oldTree.OpenElement(0, "container"); - oldTree.SetKey("original key"); - oldTree.AddContent(1, "Original"); - oldTree.CloseElement(); - - newTree.OpenElement(0, "container"); - newTree.SetKey("new key"); - newTree.AddContent(1, "Inserted"); - newTree.CloseElement(); - - // Without the key, it would change the text "Original" to "Inserted" - // With the key, it deletes the old element and inserts the new element - - // Act - var (result, referenceFrames) = GetSingleUpdatedComponent(); - - // Assert - Assert.Collection(result.Edits, - entry => - { - AssertEdit(entry, RenderTreeEditType.PrependFrame, 0); - Assert.Equal(0, entry.ReferenceFrameIndex); - Assert.Equal("new key", referenceFrames[entry.ReferenceFrameIndex].ElementKey); - }, - entry => AssertEdit(entry, RenderTreeEditType.RemoveFrame, 1)); - } - - [Fact] - public void RecognizesKeyedComponentInsertions() - { - // Arrange - oldTree.OpenComponent(0); - oldTree.SetKey("retained key"); - oldTree.AddAttribute(1, "ParamName", "Param old value"); - oldTree.CloseComponent(); - using var initial = new RenderTreeBuilder(); - GetRenderedBatch(initial, oldTree, false); // Assign initial IDs - var oldComponent = GetComponents(oldTree).Single(); - - newTree.OpenComponent(0); - newTree.SetKey("new key"); - newTree.AddAttribute(1, "ParamName", "New component param value"); - newTree.CloseComponent(); - - newTree.OpenComponent(0); - newTree.SetKey("retained key"); - newTree.AddAttribute(1, "ParamName", "Param new value"); - newTree.CloseComponent(); - - // Without the key, it would modify the param on the first component, - // then insert a new second component. - // With the key, it inserts a new first component, then modifies the - // param on the second component. - - // Act - var batchBuilder = GetRenderedBatch(initializeFromFrames: false); - var newComponents = GetComponents(newTree); - - // Assert: Inserts new component at position 0 - Assert.Equal(1, batchBuilder.UpdatedComponents.Count); - Assert.Collection(batchBuilder.UpdatedComponents.Array[0].Edits, - entry => AssertEdit(entry, RenderTreeEditType.PrependFrame, 0)); - - // Assert: Retains old component instance in position 1, and updates its params - Assert.Same(oldComponent, newComponents[1]); - Assert.Equal(2, oldComponent.SetParametersCallCount); - } - - [Fact] - public void RecognizesKeyedComponentDeletions() - { - // Arrange - oldTree.OpenComponent(0); - oldTree.SetKey("will delete"); - oldTree.AddAttribute(1, nameof(FakeComponent.StringProperty), "Anything"); - oldTree.CloseComponent(); - - oldTree.OpenComponent(0); - oldTree.SetKey("will retain"); - oldTree.AddAttribute(1, nameof(FakeComponent.StringProperty), "Retained param value"); - oldTree.CloseComponent(); - - // Instantiate initial components - using var initial = new RenderTreeBuilder(); - GetRenderedBatch(initial, oldTree, false); - var oldComponents = GetComponents(oldTree); - - newTree.OpenComponent(0); - newTree.SetKey("will retain"); - newTree.AddAttribute(1, nameof(FakeComponent.StringProperty), "Retained param value"); - newTree.CloseComponent(); - - // Without the key, it updates the param on the first component, then - // deletes the second. - // With the key, it just deletes the first. - - // Act - var (result, referenceFrames) = GetSingleUpdatedComponent(); - var newComponent = GetComponents(newTree).Single(); - - // Assert - Assert.Same(oldComponents[1], newComponent); - Assert.Collection(result.Edits, - entry => AssertEdit(entry, RenderTreeEditType.RemoveFrame, 0)); - } - - [Fact] - public void RecognizesSimultaneousKeyedComponentInsertionsAndDeletions() - { - // Arrange - oldTree.OpenComponent(0); - oldTree.SetKey("original key"); - oldTree.CloseComponent(); - - // Instantiate initial component - using var renderTreeBuilder = new RenderTreeBuilder(); - GetRenderedBatch(renderTreeBuilder, oldTree, false); - var oldComponent = GetComponents(oldTree).Single(); - Assert.NotNull(oldComponent); - - newTree.OpenComponent(0); - newTree.SetKey("new key"); - newTree.CloseComponent(); - - // Without the key, it would retain the component - // With the key, it deletes the old component and inserts the new component - - // Act - var (result, referenceFrames) = GetSingleUpdatedComponent(); - var newComponent = GetComponents(newTree).Single(); - - // Assert - Assert.NotNull(newComponent); - Assert.NotSame(oldComponent, newComponent); - Assert.Collection(result.Edits, - entry => - { - AssertEdit(entry, RenderTreeEditType.PrependFrame, 0); - Assert.Equal(0, entry.ReferenceFrameIndex); - Assert.Equal("new key", referenceFrames[entry.ReferenceFrameIndex].ComponentKey); - }, - entry => AssertEdit(entry, RenderTreeEditType.RemoveFrame, 1)); - } - - [Fact] - public void RejectsClashingKeysInOldTree() - { - // Arrange - AddWithKey(oldTree, "key1", "attrib1a"); - AddWithKey(oldTree, "key2", "attrib2"); - AddWithKey(oldTree, "key1", "attrib3"); - - AddWithKey(newTree, "key1", "attrib1b"); - AddWithKey(newTree, "key2", "attrib2"); - AddWithKey(newTree, "key3", "attrib3"); - - // Act/Assert - var ex = Assert.Throws(() => GetSingleUpdatedComponent()); - Assert.Equal("More than one sibling has the same key value, 'key1'. Key values must be unique.", ex.Message); - } - - [Fact] - public void RejectsClashingKeysInNewTree() - { - // Arrange - AddWithKey(oldTree, "key1", "attrib1a"); - AddWithKey(oldTree, "key2", "attrib2"); - AddWithKey(oldTree, "key3", "attrib3"); - - AddWithKey(newTree, "key1", "attrib1b"); - AddWithKey(newTree, "key2", "attrib2"); - AddWithKey(newTree, "key1", "attrib3"); - - // Act/Assert - var ex = Assert.Throws(() => GetSingleUpdatedComponent()); - Assert.Equal("More than one sibling has the same key value, 'key1'. Key values must be unique.", ex.Message); - } - - [Fact] - public void RejectsClashingKeysEvenIfAllPairsMatch() - { - // This sort of scenario would happen if you accidentally used a constant value for @key - - // Arrange - AddWithKey(oldTree, "key1", "attrib1a"); - AddWithKey(oldTree, "key1", "attrib1b"); - - AddWithKey(newTree, "key1", "attrib1a"); - AddWithKey(newTree, "key1", "attrib1b"); - - // Act/Assert - var ex = Assert.Throws(() => GetSingleUpdatedComponent()); - Assert.Equal("More than one sibling has the same key value, 'key1'. Key values must be unique.", ex.Message); - } - - [Fact] - public void HandlesInsertionOfUnkeyedItemsAroundKey() - { - // The fact that the new sequence numbers are descending makes this - // problematic if it prefers matching by sequence over key. - // However, since the policy is to prefer key over sequence, it works OK. - - // Arrange - oldTree.OpenElement(1, "el"); - oldTree.SetKey("some key"); - oldTree.CloseElement(); - - newTree.OpenElement(2, "other"); - newTree.CloseElement(); - - newTree.OpenElement(1, "el"); - newTree.SetKey("some key"); - newTree.CloseElement(); - - newTree.OpenElement(0, "other 2"); - newTree.CloseElement(); - - // Act - var (result, referenceFrames) = GetSingleUpdatedComponent(); - - // Assert - Assert.Collection(result.Edits, - edit => AssertEdit(edit, RenderTreeEditType.PrependFrame, 0), - edit => AssertEdit(edit, RenderTreeEditType.PrependFrame, 2)); - } - - [Fact] - public void HandlesDeletionOfUnkeyedItemsAroundKey() - { - // The fact that the old sequence numbers are descending makes this - // problematic if it prefers matching by sequence over key. - // However, since the policy is to prefer key over sequence, it works OK. - - // Arrange - oldTree.OpenElement(2, "other"); - oldTree.CloseElement(); - - oldTree.OpenElement(1, "el"); - oldTree.SetKey("some key"); - oldTree.CloseElement(); - - oldTree.OpenElement(0, "other 2"); - oldTree.CloseElement(); - - newTree.OpenElement(1, "el"); - newTree.SetKey("some key"); - newTree.CloseElement(); - - // Act - var (result, referenceFrames) = GetSingleUpdatedComponent(); - - // Assert - Assert.Collection(result.Edits, - edit => AssertEdit(edit, RenderTreeEditType.RemoveFrame, 0), - edit => AssertEdit(edit, RenderTreeEditType.RemoveFrame, 1)); - } - - [Fact] - public void HandlesKeyBeingAdded() - { - // This is an anomolous situation that can't occur with .razor components. - // It represents the case where, for the same sequence number, we have an - // old frame without a key and a new frame with a key. - - // Arrange - oldTree.OpenElement(0, "el"); - oldTree.CloseElement(); - - newTree.OpenElement(0, "el"); - newTree.SetKey("some key"); - newTree.CloseElement(); - - // Act - var (result, referenceFrames) = GetSingleUpdatedComponent(); - - // Assert - Assert.Collection(result.Edits, - // Insert new - edit => - { - AssertEdit(edit, RenderTreeEditType.PrependFrame, 0); - Assert.Equal("some key", referenceFrames[edit.ReferenceFrameIndex].ElementKey); - }, - // Delete old - edit => AssertEdit(edit, RenderTreeEditType.RemoveFrame, 1)); - } - - [Fact] - public void HandlesKeyBeingRemoved() - { - // This is an anomolous situation that can't occur with .razor components. - // It represents the case where, for the same sequence number, we have an - // old frame with a key and a new frame without a key. - - // Arrange - oldTree.OpenElement(0, "el"); - oldTree.SetKey("some key"); - oldTree.CloseElement(); - - newTree.OpenElement(0, "el"); - newTree.CloseElement(); - - // Act - var (result, referenceFrames) = GetSingleUpdatedComponent(); - - // Assert - Assert.Collection(result.Edits, - // Insert new - edit => AssertEdit(edit, RenderTreeEditType.PrependFrame, 0), - // Delete old - edit => AssertEdit(edit, RenderTreeEditType.RemoveFrame, 1)); - } - - [Fact] - public void RecognizesTrailingSequenceWithinLoopBlockBeingRemoved() - { - // Arrange - oldTree.AddContent(0, "x"); // Loop start - oldTree.AddContent(1, "x"); // Will be removed - oldTree.AddContent(2, "x"); // Will be removed - oldTree.AddContent(0, "x"); // Loop start - newTree.AddContent(0, "x"); // Loop start - newTree.AddContent(0, "x"); // Loop start - - // Act - var (result, referenceFrames) = GetSingleUpdatedComponent(); - - // Assert - Assert.Collection(result.Edits, - entry => AssertEdit(entry, RenderTreeEditType.RemoveFrame, 1), - entry => AssertEdit(entry, RenderTreeEditType.RemoveFrame, 1)); - } - - [Fact] - public void RecognizesTrailingSequenceWithinLoopBlockBeingAppended() - { - // Arrange - oldTree.AddContent(10, "x"); // Loop start - oldTree.AddContent(10, "x"); // Loop start - newTree.AddContent(10, "x"); // Loop start - newTree.AddContent(11, "x"); // Will be added - newTree.AddContent(12, "x"); // Will be added - newTree.AddContent(10, "x"); // Loop start - - // Act - var (result, referenceFrames) = GetSingleUpdatedComponent(); - - // Assert - Assert.Collection(result.Edits, - entry => - { - AssertEdit(entry, RenderTreeEditType.PrependFrame, 1); - Assert.Equal(0, entry.ReferenceFrameIndex); - }, - entry => - { - AssertEdit(entry, RenderTreeEditType.PrependFrame, 2); - Assert.Equal(1, entry.ReferenceFrameIndex); - }); - AssertFrame.Text(referenceFrames[0], "x", 11); - AssertFrame.Text(referenceFrames[1], "x", 12); - } - - [Fact] - public void RecognizesTrailingLoopBlockBeingRemoved() - { - // Arrange - oldTree.AddContent(0, "x"); - oldTree.AddContent(1, "x"); - oldTree.AddContent(0, "x"); // Will be removed - oldTree.AddContent(1, "x"); // Will be removed - newTree.AddContent(0, "x"); - newTree.AddContent(1, "x"); - - // Act - var (result, referenceFrames) = GetSingleUpdatedComponent(); - - // Assert - Assert.Collection(result.Edits, - entry => AssertEdit(entry, RenderTreeEditType.RemoveFrame, 2), - entry => AssertEdit(entry, RenderTreeEditType.RemoveFrame, 2)); - } - - [Fact] - public void RecognizesTrailingLoopBlockBeingAdded() - { - // Arrange - oldTree.AddContent(10, "x"); - oldTree.AddContent(11, "x"); - newTree.AddContent(10, "x"); - newTree.AddContent(11, "x"); - newTree.AddContent(10, "x"); // Will be added - newTree.AddContent(11, "x"); // Will be added - - // Act - var (result, referenceFrames) = GetSingleUpdatedComponent(); - - // Assert - Assert.Collection(result.Edits, - entry => - { - AssertEdit(entry, RenderTreeEditType.PrependFrame, 2); - Assert.Equal(0, entry.ReferenceFrameIndex); - }, - entry => - { - AssertEdit(entry, RenderTreeEditType.PrependFrame, 3); - Assert.Equal(1, entry.ReferenceFrameIndex); - }); - AssertFrame.Text(referenceFrames[0], "x", 10); - AssertFrame.Text(referenceFrames[1], "x", 11); - } - - [Fact] - public void RecognizesLeadingLoopBlockItemsBeingAdded() - { - // Arrange - oldTree.AddContent(12, "x"); - oldTree.AddContent(12, "x"); // Note that the '0' and '1' items are not present on this iteration - newTree.AddContent(12, "x"); - newTree.AddContent(10, "x"); - newTree.AddContent(11, "x"); - newTree.AddContent(12, "x"); - - // Act - var (result, referenceFrames) = GetSingleUpdatedComponent(); - - // Assert - Assert.Collection(result.Edits, - entry => - { - AssertEdit(entry, RenderTreeEditType.PrependFrame, 1); - Assert.Equal(0, entry.ReferenceFrameIndex); - }, - entry => - { - AssertEdit(entry, RenderTreeEditType.PrependFrame, 2); - Assert.Equal(1, entry.ReferenceFrameIndex); - }); - AssertFrame.Text(referenceFrames[0], "x", 10); - AssertFrame.Text(referenceFrames[1], "x", 11); - } - - [Fact] - public void RecognizesLeadingLoopBlockItemsBeingRemoved() - { - // Arrange - oldTree.AddContent(2, "x"); - oldTree.AddContent(0, "x"); - oldTree.AddContent(1, "x"); - oldTree.AddContent(2, "x"); - newTree.AddContent(2, "x"); - newTree.AddContent(2, "x"); // Note that the '0' and '1' items are not present on this iteration - - // Act - var (result, referenceFrames) = GetSingleUpdatedComponent(); - - // Assert - Assert.Collection(result.Edits, - entry => AssertEdit(entry, RenderTreeEditType.RemoveFrame, 1), - entry => AssertEdit(entry, RenderTreeEditType.RemoveFrame, 1)); - } - - [Fact] - public void HandlesAdjacentItemsBeingRemovedAndInsertedAtOnce() - { - // Arrange - oldTree.AddContent(0, "text"); - newTree.AddContent(1, "text"); - - // Act - var (result, referenceFrames) = GetSingleUpdatedComponent(); - - // Assert - Assert.Collection(result.Edits, - entry => AssertEdit(entry, RenderTreeEditType.RemoveFrame, 0), - entry => AssertEdit(entry, RenderTreeEditType.PrependFrame, 0)); - } - - [Fact] - public void RecognizesTextUpdates() - { - // Arrange - oldTree.AddContent(123, "old text 1"); - oldTree.AddContent(182, "old text 2"); - newTree.AddContent(123, "new text 1"); - newTree.AddContent(182, "new text 2"); - - // Act - var (result, referenceFrames) = GetSingleUpdatedComponent(); - - // Assert - Assert.Collection(result.Edits, - entry => - { - AssertEdit(entry, RenderTreeEditType.UpdateText, 0); - Assert.Equal(0, entry.ReferenceFrameIndex); - }, - entry => - { - AssertEdit(entry, RenderTreeEditType.UpdateText, 1); - Assert.Equal(1, entry.ReferenceFrameIndex); - }); - } - - [Fact] - public void RecognizesMarkupChanges() - { - // Arrange - oldTree.AddMarkupContent(1, "preserved"); - oldTree.AddMarkupContent(3, "will be updated"); - oldTree.AddMarkupContent(4, "will be removed"); - newTree.AddMarkupContent(1, "preserved"); - newTree.AddMarkupContent(2, "was inserted"); - newTree.AddMarkupContent(3, "was updated"); - - // Act - var (result, referenceFrames) = GetSingleUpdatedComponent(); - - // Assert - Assert.Collection(result.Edits, - entry => - { - AssertEdit(entry, RenderTreeEditType.PrependFrame, 1); - Assert.Equal(0, entry.ReferenceFrameIndex); - Assert.Equal("was inserted", referenceFrames[entry.ReferenceFrameIndex].MarkupContent); - }, - entry => - { - AssertEdit(entry, RenderTreeEditType.UpdateMarkup, 2); - Assert.Equal(1, entry.ReferenceFrameIndex); - Assert.Equal("was updated", referenceFrames[entry.ReferenceFrameIndex].MarkupContent); - }, - entry => - { - AssertEdit(entry, RenderTreeEditType.RemoveFrame, 3); - }); - } - - [Fact] - public void RecognizesElementNameChangesAtSameSequenceNumber() - { - // Note: It's not possible to trigger this scenario from a Razor component, because - // a given source sequence can only have a single fixed element name. We might later - // decide just to throw in this scenario, since it's unnecessary to support it. - - // Arrange - oldTree.OpenElement(123, "old element"); - oldTree.CloseElement(); - newTree.OpenElement(123, "new element"); - newTree.CloseElement(); - - // Act - var (result, referenceFrames) = GetSingleUpdatedComponent(); - - // Assert - Assert.Collection(result.Edits, - entry => AssertEdit(entry, RenderTreeEditType.RemoveFrame, 0), - entry => - { - AssertEdit(entry, RenderTreeEditType.PrependFrame, 0); - Assert.Equal(0, entry.ReferenceFrameIndex); - }); - } - - [Fact] - public void RecognizesComponentTypeChangesAtSameSequenceNumber() - { - // Arrange - oldTree.OpenComponent(123); - oldTree.CloseComponent(); - using var initial = new RenderTreeBuilder(); - GetRenderedBatch(initial, oldTree, false); // Assign initial IDs - newTree.OpenComponent(123); - newTree.CloseComponent(); - using var batchBuilder = new RenderBatchBuilder(); - - // Act - var diff = RenderTreeDiffBuilder.ComputeDiff(renderer, batchBuilder, 0, oldTree.GetFrames(), newTree.GetFrames()); - - // Assert: We're going to dispose the old component and render the new one - Assert.Equal(new[] { 0 }, batchBuilder.ComponentDisposalQueue); - Assert.Collection(diff.Edits, - entry => AssertEdit(entry, RenderTreeEditType.RemoveFrame, 0), - entry => - { - AssertEdit(entry, RenderTreeEditType.PrependFrame, 0); - Assert.IsType(batchBuilder.ReferenceFramesBuffer.Buffer[entry.ReferenceFrameIndex].Component); - }); - } - - [Fact] - public void RecognizesAttributesAdded() - { - // Arrange - oldTree.OpenElement(0, "My element"); - oldTree.AddAttribute(1, "existing", "existing value"); - oldTree.CloseElement(); - newTree.OpenElement(0, "My element"); - newTree.AddAttribute(1, "existing", "existing value"); - newTree.AddAttribute(2, "added", "added value"); - newTree.CloseElement(); - - // Act - var (result, referenceFrames) = GetSingleUpdatedComponent(); - - // Assert - Assert.Collection(result.Edits, - entry => - { - AssertEdit(entry, RenderTreeEditType.SetAttribute, 0); - Assert.Equal(0, entry.ReferenceFrameIndex); - }); - AssertFrame.Attribute(referenceFrames[0], "added", "added value"); - } - - [Fact] - public void RecognizesAttributesRemoved() - { - // Arrange - oldTree.OpenElement(0, "My element"); - oldTree.AddAttribute(1, "will be removed", "will be removed value"); - oldTree.AddAttribute(2, "will survive", "surviving value"); - oldTree.CloseElement(); - newTree.OpenElement(0, "My element"); - newTree.AddAttribute(2, "will survive", "surviving value"); - newTree.CloseElement(); - - // Act - var (result, referenceFrames) = GetSingleUpdatedComponent(); - - // Assert - Assert.Collection(result.Edits, - entry => - { - AssertEdit(entry, RenderTreeEditType.RemoveAttribute, 0); - Assert.Equal("will be removed", entry.RemovedAttributeName); - }); - } - - [Fact] - public void RecognizesAttributeStringValuesChanged() - { - // Arrange - oldTree.OpenElement(0, "My element"); - oldTree.AddAttribute(1, "will remain", "will remain value"); - oldTree.AddAttribute(2, "will change", "will change value"); - oldTree.CloseElement(); - newTree.OpenElement(0, "My element"); - newTree.AddAttribute(1, "will remain", "will remain value"); - newTree.AddAttribute(2, "will change", "did change value"); - newTree.CloseElement(); - - // Act - var (result, referenceFrames) = GetSingleUpdatedComponent(); - - // Assert - Assert.Collection(result.Edits, - entry => - { - AssertEdit(entry, RenderTreeEditType.SetAttribute, 0); - Assert.Equal(0, entry.ReferenceFrameIndex); - }); - AssertFrame.Attribute(referenceFrames[0], "will change", "did change value"); - } - - [Fact] - public void RecognizesAttributeEventHandlerValuesChanged() - { - // Arrange - Action retainedHandler = _ => { }; - Action removedHandler = _ => { }; - Action addedHandler = _ => { }; - oldTree.OpenElement(0, "My element"); - oldTree.AddAttribute(1, "onfoo", retainedHandler); - oldTree.AddAttribute(2, "onbar", removedHandler); - oldTree.CloseElement(); - newTree.OpenElement(0, "My element"); - newTree.AddAttribute(1, "onfoo", retainedHandler); - newTree.AddAttribute(2, "onbar", addedHandler); - newTree.CloseElement(); - - // Act - var (result, referenceFrames, batchBuilder) = GetSingleUpdatedComponentWithBatch(initializeFromFrames: true); - var removedEventHandlerFrame = oldTree.GetFrames().Array[2]; - - // Assert - Assert.Collection(result.Edits, - entry => - { - AssertEdit(entry, RenderTreeEditType.SetAttribute, 0); - Assert.Equal(0, entry.ReferenceFrameIndex); - }); - AssertFrame.Attribute(referenceFrames[0], "onbar", addedHandler); - Assert.NotEqual(default, removedEventHandlerFrame.AttributeEventHandlerId); - Assert.Equal( - new[] { removedEventHandlerFrame.AttributeEventHandlerId }, - batchBuilder.DisposedEventHandlerIDs.AsEnumerable()); - } - - [Fact] - public void RecognizesAttributeNamesChangedAtSameSourceSequence() - { - // Arrange - oldTree.OpenElement(0, "My element"); - oldTree.AddAttribute(1, "oldname", "same value"); - oldTree.CloseElement(); - newTree.OpenElement(0, "My element"); - newTree.AddAttribute(1, "newname", "same value"); - newTree.CloseElement(); - - // Act - var (result, referenceFrames) = GetSingleUpdatedComponent(); - - // Assert - Assert.Collection(result.Edits, - entry => - { - AssertEdit(entry, RenderTreeEditType.RemoveAttribute, 0); - Assert.Equal("oldname", entry.RemovedAttributeName); - }, - entry => - { - AssertEdit(entry, RenderTreeEditType.SetAttribute, 0); - Assert.Equal(0, entry.ReferenceFrameIndex); - }); - AssertFrame.Attribute(referenceFrames[0], "newname", "same value"); - } - - [Fact] - public void AttributeDiff_WithSameSequenceNumber_AttributeAddedAtStart() - { - // Arrange - oldTree.OpenElement(0, "My element"); - oldTree.AddAttribute(0, "attr2", "value2"); - oldTree.AddAttribute(0, "attr3", "value3"); - oldTree.CloseElement(); - newTree.OpenElement(0, "My element"); - newTree.AddAttribute(0, "attr1", "value1"); - newTree.AddAttribute(0, "attr2", "value2"); - newTree.AddAttribute(0, "attr3", "value3"); - newTree.CloseElement(); - - // Act - var (result, referenceFrames) = GetSingleUpdatedComponent(); - - // Assert - Assert.Collection( - result.Edits, - entry => - { - AssertEdit(entry, RenderTreeEditType.SetAttribute, 0); - Assert.Equal(0, entry.ReferenceFrameIndex); - }); - Assert.Collection( - referenceFrames, - frame => AssertFrame.Attribute(frame, "attr1", 0)); - } - - [Fact] - public void AttributeDiff_WithSameSequenceNumber_AttributeAddedInMiddle() - { - // Arrange - oldTree.OpenElement(0, "My element"); - oldTree.AddAttribute(0, "attr1", "value1"); - oldTree.AddAttribute(0, "attr3", "value3"); - oldTree.CloseElement(); - newTree.OpenElement(0, "My element"); - newTree.AddAttribute(0, "attr1", "value1"); - newTree.AddAttribute(0, "attr2", "value2"); - newTree.AddAttribute(0, "attr3", "value3"); - newTree.CloseElement(); - - // Act - var (result, referenceFrames) = GetSingleUpdatedComponent(); - - // Assert - Assert.Collection( - result.Edits, - entry => - { - AssertEdit(entry, RenderTreeEditType.SetAttribute, 0); - Assert.Equal(0, entry.ReferenceFrameIndex); - }); - - Assert.Collection( - referenceFrames, - frame => AssertFrame.Attribute(frame, "attr2", 0)); - } - - [Fact] - public void AttributeDiff_WithSameSequenceNumber_AttributeAddedAtEnd() - { - // Arrange - oldTree.OpenElement(0, "My element"); - oldTree.AddAttribute(0, "attr1", "value1"); - oldTree.AddAttribute(0, "attr2", "value2"); - oldTree.CloseElement(); - newTree.OpenElement(0, "My element"); - newTree.AddAttribute(0, "attr1", "value1"); - newTree.AddAttribute(0, "attr2", "value2"); - newTree.AddAttribute(0, "attr3", "value3"); - newTree.CloseElement(); - - // Act - var (result, referenceFrames) = GetSingleUpdatedComponent(); - - // Assert - Assert.Collection( - result.Edits, - entry => - { - AssertEdit(entry, RenderTreeEditType.SetAttribute, 0); - Assert.Equal(0, entry.ReferenceFrameIndex); - }); - - Assert.Collection( - referenceFrames, - frame => AssertFrame.Attribute(frame, "attr3", 0)); - } - - [Fact] - public void AttributeDiff_WithSequentialSequenceNumber_AttributeAddedAtStart() - { - // Arrange - oldTree.OpenElement(0, "My element"); - oldTree.AddAttribute(2, "attr2", "value2"); - oldTree.AddAttribute(3, "attr3", "value3"); - oldTree.CloseElement(); - newTree.OpenElement(0, "My element"); - newTree.AddAttribute(1, "attr1", "value1"); - newTree.AddAttribute(2, "attr2", "value2"); - newTree.AddAttribute(3, "attr3", "value3"); - newTree.CloseElement(); - - // Act - var (result, referenceFrames) = GetSingleUpdatedComponent(); - - // Assert - Assert.Collection( - result.Edits, - entry => - { - AssertEdit(entry, RenderTreeEditType.SetAttribute, 0); - Assert.Equal(0, entry.ReferenceFrameIndex); - }); - Assert.Collection( - referenceFrames, - frame => AssertFrame.Attribute(frame, "attr1", 1)); - } - - [Fact] - public void AttributeDiff_WithSequentialSequenceNumber_AttributeAddedInMiddle() - { - // Arrange - oldTree.OpenElement(0, "My element"); - oldTree.AddAttribute(1, "attr1", "value1"); - oldTree.AddAttribute(3, "attr3", "value3"); - oldTree.CloseElement(); - newTree.OpenElement(0, "My element"); - newTree.AddAttribute(1, "attr1", "value1"); - newTree.AddAttribute(2, "attr2", "value2"); - newTree.AddAttribute(3, "attr3", "value3"); - newTree.CloseElement(); - - // Act - var (result, referenceFrames) = GetSingleUpdatedComponent(); - - // Assert - Assert.Collection( - result.Edits, - entry => - { - AssertEdit(entry, RenderTreeEditType.SetAttribute, 0); - Assert.Equal(0, entry.ReferenceFrameIndex); - }); - - Assert.Collection( - referenceFrames, - frame => AssertFrame.Attribute(frame, "attr2", 2)); - } - - [Fact] - public void AttributeDiff_WithSequentialSequenceNumber_AttributeAddedAtEnd() - { - // Arrange - oldTree.OpenElement(0, "My element"); - oldTree.AddAttribute(1, "attr1", "value1"); - oldTree.AddAttribute(2, "attr2", "value2"); - oldTree.CloseElement(); - newTree.OpenElement(0, "My element"); - newTree.AddAttribute(1, "attr1", "value1"); - newTree.AddAttribute(2, "attr2", "value2"); - newTree.AddAttribute(3, "attr3", "value3"); - newTree.CloseElement(); - - // Act - var (result, referenceFrames) = GetSingleUpdatedComponent(); - - // Assert - Assert.Collection( - result.Edits, - entry => - { - AssertEdit(entry, RenderTreeEditType.SetAttribute, 0); - Assert.Equal(0, entry.ReferenceFrameIndex); - }); - - Assert.Collection( - referenceFrames, - frame => AssertFrame.Attribute(frame, "attr3", 3)); - } - - [Fact] - public void AttributeDiff_WithSameSequenceNumber_AttributeRemovedAtStart() - { - // Arrange - oldTree.OpenElement(0, "My element"); - oldTree.AddAttribute(0, "attr1", "value1"); - oldTree.AddAttribute(0, "attr2", "value2"); - oldTree.AddAttribute(0, "attr3", "value3"); - oldTree.CloseElement(); - newTree.OpenElement(0, "My element"); - newTree.AddAttribute(0, "attr2", "value2"); - newTree.AddAttribute(0, "attr3", "value3"); - newTree.CloseElement(); - - // Act - var (result, referenceFrames) = GetSingleUpdatedComponent(); - - // Assert - Assert.Collection( - result.Edits, - entry => - { - AssertEdit(entry, RenderTreeEditType.RemoveAttribute, 0); - Assert.Equal("attr1", entry.RemovedAttributeName); - }); - } - - [Fact] - public void AttributeDiff_WithSameSequenceNumber_AttributeRemovedInMiddle() - { - // Arrange - oldTree.OpenElement(0, "My element"); - oldTree.AddAttribute(0, "attr1", "value1"); - oldTree.AddAttribute(0, "attr2", "value2"); - oldTree.AddAttribute(0, "attr3", "value3"); - oldTree.CloseElement(); - newTree.OpenElement(0, "My element"); - newTree.AddAttribute(0, "attr1", "value1"); - newTree.AddAttribute(0, "attr3", "value3"); - newTree.CloseElement(); - - // Act - var (result, referenceFrames) = GetSingleUpdatedComponent(); - - // Assert - Assert.Collection( - result.Edits, - entry => - { - AssertEdit(entry, RenderTreeEditType.RemoveAttribute, 0); - Assert.Equal("attr2", entry.RemovedAttributeName); - }); - } - - [Fact] - public void AttributeDiff_WithSameSequenceNumber_AttributeRemovedAtEnd() - { - // Arrange - oldTree.OpenElement(0, "My element"); - oldTree.AddAttribute(0, "attr1", "value1"); - oldTree.AddAttribute(0, "attr2", "value2"); - oldTree.AddAttribute(0, "attr3", "value3"); - oldTree.CloseElement(); - newTree.OpenElement(0, "My element"); - newTree.AddAttribute(0, "attr1", "value1"); - newTree.AddAttribute(0, "attr2", "value2"); - newTree.CloseElement(); - - // Act - var (result, referenceFrames) = GetSingleUpdatedComponent(); - - // Assert - Assert.Collection( - result.Edits, - entry => - { - AssertEdit(entry, RenderTreeEditType.RemoveAttribute, 0); - Assert.Equal("attr3", entry.RemovedAttributeName); - }); - } - - [Fact] - public void AttributeDiff_WithSequentialSequenceNumber_AttributeRemovedAtStart() - { - // Arrange - oldTree.OpenElement(0, "My element"); - oldTree.AddAttribute(1, "attr1", "value1"); - oldTree.AddAttribute(2, "attr2", "value2"); - oldTree.AddAttribute(3, "attr3", "value3"); - oldTree.CloseElement(); - newTree.OpenElement(0, "My element"); - newTree.AddAttribute(2, "attr2", "value2"); - newTree.AddAttribute(3, "attr3", "value3"); - newTree.CloseElement(); - - // Act - var (result, referenceFrames) = GetSingleUpdatedComponent(); - - // Assert - Assert.Collection( - result.Edits, - entry => - { - AssertEdit(entry, RenderTreeEditType.RemoveAttribute, 0); - Assert.Equal("attr1", entry.RemovedAttributeName); - }); - } - - [Fact] - public void AttributeDiff_WithSequentialSequenceNumber_AttributeRemovedInMiddle() - { - // Arrange - oldTree.OpenElement(0, "My element"); - oldTree.AddAttribute(1, "attr1", "value1"); - oldTree.AddAttribute(2, "attr2", "value2"); - oldTree.AddAttribute(3, "attr3", "value3"); - oldTree.CloseElement(); - newTree.OpenElement(0, "My element"); - newTree.AddAttribute(1, "attr1", "value1"); - newTree.AddAttribute(3, "attr3", "value3"); - newTree.CloseElement(); - - // Act - var (result, referenceFrames) = GetSingleUpdatedComponent(); - - // Assert - Assert.Collection( - result.Edits, - entry => - { - AssertEdit(entry, RenderTreeEditType.RemoveAttribute, 0); - Assert.Equal("attr2", entry.RemovedAttributeName); - }); - } - - [Fact] - public void AttributeDiff_WithSequentialSequenceNumber_AttributeRemovedAtEnd() - { - // Arrange - oldTree.OpenElement(0, "My element"); - oldTree.AddAttribute(1, "attr1", "value1"); - oldTree.AddAttribute(2, "attr2", "value2"); - oldTree.AddAttribute(3, "attr3", "value3"); - oldTree.CloseElement(); - newTree.OpenElement(0, "My element"); - newTree.AddAttribute(1, "attr1", "value1"); - newTree.AddAttribute(2, "attr2", "value2"); - newTree.CloseElement(); - - // Act - var (result, referenceFrames) = GetSingleUpdatedComponent(); - - // Assert - Assert.Collection( - result.Edits, - entry => - { - AssertEdit(entry, RenderTreeEditType.RemoveAttribute, 0); - Assert.Equal("attr3", entry.RemovedAttributeName); - }); - } - - [Fact] - public void DiffsElementsHierarchically() - { - // Arrange - oldTree.AddContent(09, "unrelated"); - oldTree.OpenElement(10, "root"); - oldTree.OpenElement(11, "child"); - oldTree.OpenElement(12, "grandchild"); - oldTree.AddContent(13, "grandchild old text"); - oldTree.CloseElement(); - oldTree.CloseElement(); - oldTree.CloseElement(); - - newTree.AddContent(09, "unrelated"); - newTree.OpenElement(10, "root"); - newTree.OpenElement(11, "child"); - newTree.OpenElement(12, "grandchild"); - newTree.AddContent(13, "grandchild new text"); - newTree.CloseElement(); - newTree.CloseElement(); - newTree.CloseElement(); - - // Act - var (result, referenceFrames) = GetSingleUpdatedComponent(); - - // Assert - Assert.Collection(result.Edits, - entry => AssertEdit(entry, RenderTreeEditType.StepIn, 1), - entry => AssertEdit(entry, RenderTreeEditType.StepIn, 0), - entry => AssertEdit(entry, RenderTreeEditType.StepIn, 0), - entry => - { - AssertEdit(entry, RenderTreeEditType.UpdateText, 0); - Assert.Equal(0, entry.ReferenceFrameIndex); - }, - entry => AssertEdit(entry, RenderTreeEditType.StepOut, 0), - entry => AssertEdit(entry, RenderTreeEditType.StepOut, 0), - entry => AssertEdit(entry, RenderTreeEditType.StepOut, 0)); - AssertFrame.Text(referenceFrames[0], "grandchild new text", 13); - } - - [Fact] - public void SkipsUnmodifiedSubtrees() - { - // Arrange - oldTree.OpenElement(10, "root"); - oldTree.AddContent(11, "Text that will change"); - oldTree.OpenElement(12, "Subtree that will not change"); - oldTree.OpenElement(13, "Another"); - oldTree.AddContent(14, "Text that will not change"); - oldTree.CloseElement(); - oldTree.CloseElement(); - oldTree.CloseElement(); - - newTree.OpenElement(10, "root"); - newTree.AddContent(11, "Text that has changed"); - newTree.OpenElement(12, "Subtree that will not change"); - newTree.OpenElement(13, "Another"); - newTree.AddContent(14, "Text that will not change"); - newTree.CloseElement(); - newTree.CloseElement(); - newTree.CloseElement(); - - // Act - var (result, referenceFrames) = GetSingleUpdatedComponent(); - - // Assert - Assert.Collection(result.Edits, - entry => AssertEdit(entry, RenderTreeEditType.StepIn, 0), - entry => - { - AssertEdit(entry, RenderTreeEditType.UpdateText, 0); - Assert.Equal(0, entry.ReferenceFrameIndex); - }, - entry => AssertEdit(entry, RenderTreeEditType.StepOut, 0)); - AssertFrame.Text(referenceFrames[0], "Text that has changed", 11); - } - - [Fact] - public void SkipsUnmodifiedTrailingSiblings() - { - // Arrange - oldTree.AddContent(10, "text1"); - oldTree.AddContent(11, "text2"); - oldTree.AddContent(12, "text3"); - oldTree.AddContent(13, "text4"); - newTree.AddContent(10, "text1"); - newTree.AddContent(11, "text2modified"); - newTree.AddContent(12, "text3"); - newTree.AddContent(13, "text4"); - - // Act - var (result, referenceFrames) = GetSingleUpdatedComponent(); - - // Assert - Assert.Collection(result.Edits, - entry => - { - AssertEdit(entry, RenderTreeEditType.UpdateText, 1); - Assert.Equal(0, entry.ReferenceFrameIndex); - }); - AssertFrame.Text(referenceFrames[0], "text2modified", 11); - } - - [Fact] - public void PassesThroughRegionsInsidePrependedElements() - { - // Arrange - oldTree.AddContent(0, "Will not change"); - newTree.AddContent(0, "Will not change"); - newTree.OpenElement(1, "root"); - newTree.OpenRegion(2); - newTree.AddContent(0, "text1"); - newTree.CloseRegion(); - newTree.CloseElement(); - - // Act - var (result, referenceFrames) = GetSingleUpdatedComponent(); - - // Assert - Assert.Collection(result.Edits, - entry => - { - AssertEdit(entry, RenderTreeEditType.PrependFrame, 1); - Assert.Equal(0, entry.ReferenceFrameIndex); - }); - Assert.Collection(referenceFrames, - frame => AssertFrame.Element(frame, "root", 3, 1), - frame => AssertFrame.Region(frame, 2, 2), - frame => AssertFrame.Text(frame, "text1")); - } - - [Fact] - public void RecognizesInsertedRegions() - { - // Arrange - oldTree.AddContent(1, "Start"); - oldTree.AddContent(3, "End"); - newTree.AddContent(1, "Start"); - newTree.OpenRegion(2); - newTree.AddContent(4, "Text inside region"); // Sequence number is unrelated to outside the region - newTree.OpenRegion(5); - newTree.AddContent(6, "Text inside nested region"); - newTree.CloseRegion(); - newTree.CloseRegion(); - newTree.AddContent(3, "End"); - - // Act - var (result, referenceFrames) = GetSingleUpdatedComponent(); - - // Assert - Assert.Collection(result.Edits, - entry => - { - AssertEdit(entry, RenderTreeEditType.PrependFrame, 1); - AssertFrame.Text( - referenceFrames[entry.ReferenceFrameIndex], "Text inside region"); - }, - entry => - { - AssertEdit(entry, RenderTreeEditType.PrependFrame, 2); - AssertFrame.Text( - referenceFrames[entry.ReferenceFrameIndex], "Text inside nested region"); - }); - } - - [Fact] - public void RecognizesRemovedRegions() - { - // Arrange - oldTree.AddContent(1, "Start"); - oldTree.OpenRegion(2); - oldTree.AddContent(4, "Text inside region"); // Sequence number is unrelated to outside the region - oldTree.OpenRegion(5); - oldTree.AddContent(6, "Text inside nested region"); - oldTree.CloseRegion(); - oldTree.CloseRegion(); - oldTree.AddContent(3, "End"); - newTree.AddContent(1, "Start"); - newTree.AddContent(3, "End"); - - // Act - var (result, referenceFrames) = GetSingleUpdatedComponent(); - - // Assert - Assert.Collection(result.Edits, - entry => AssertEdit(entry, RenderTreeEditType.RemoveFrame, 1), - entry => AssertEdit(entry, RenderTreeEditType.RemoveFrame, 1)); - } - - [Fact] - public void RecognizesEquivalentRegions() - { - // Arrange - oldTree.AddContent(1, "Start"); - oldTree.OpenRegion(2); - oldTree.AddContent(4, "Text inside region"); - oldTree.AddContent(5, "Text to move"); - oldTree.OpenRegion(6); - oldTree.CloseRegion(); - oldTree.CloseRegion(); - oldTree.AddContent(3, "End"); - newTree.AddContent(1, "Start"); - newTree.OpenRegion(2); - newTree.AddContent(4, "Changed text inside region"); - newTree.OpenRegion(6); - newTree.AddContent(5, "Text to move"); // Although it's the same sequence and content, it's now in a different region so not the same - newTree.CloseRegion(); - newTree.CloseRegion(); - newTree.AddContent(3, "End"); - - // Act - var (result, referenceFrames) = GetSingleUpdatedComponent(); - - // Assert - Assert.Collection(result.Edits, - entry => - { - AssertEdit(entry, RenderTreeEditType.UpdateText, 1); - AssertFrame.Text( - referenceFrames[entry.ReferenceFrameIndex], "Changed text inside region"); - }, - entry => AssertEdit(entry, RenderTreeEditType.RemoveFrame, 2), - entry => - { - AssertEdit(entry, RenderTreeEditType.PrependFrame, 2); - AssertFrame.Text( - referenceFrames[entry.ReferenceFrameIndex], "Text to move"); - }); - } - - [Fact] - public void InstantiatesChildComponentsForInsertedFrames() - { - // Arrange - oldTree.AddContent(10, "text1"); // 0: text1 - oldTree.OpenElement(11, "container"); // 1: - oldTree.CloseElement(); // - newTree.AddContent(10, "text1"); // 0: text1 - newTree.OpenElement(11, "container"); // 1: - newTree.OpenComponent(12); // 2: - newTree.CloseComponent(); // - newTree.OpenComponent(13); // 3: - newTree.CloseComponent(); // - newTree.CloseElement(); // - - // Act - var renderBatch = GetRenderedBatch(); - - // Assert - var diff = renderBatch.UpdatedComponents.AsEnumerable().Single(); - Assert.Collection(diff.Edits, - entry => AssertEdit(entry, RenderTreeEditType.StepIn, 1), - entry => - { - AssertEdit(entry, RenderTreeEditType.PrependFrame, 0); - Assert.Equal(0, entry.ReferenceFrameIndex); - }, - entry => - { - AssertEdit(entry, RenderTreeEditType.PrependFrame, 1); - Assert.Equal(1, entry.ReferenceFrameIndex); - }, - entry => AssertEdit(entry, RenderTreeEditType.StepOut, 0)); - AssertFrame.ComponentWithInstance(renderBatch.ReferenceFrames.Array[0], 0, null, 12); - AssertFrame.ComponentWithInstance(renderBatch.ReferenceFrames.Array[1], 1, null, 13); - } - - [Fact] - public void SetsParametersOnChildComponents() - { - // Arrange - var testObject = new object(); - newTree.OpenComponent(0); - newTree.AddAttribute(1, nameof(FakeComponent.IntProperty), 123); - newTree.AddAttribute(2, nameof(FakeComponent.StringProperty), "some string"); - newTree.AddAttribute(3, nameof(FakeComponent.ObjectProperty), testObject); - newTree.CloseComponent(); - - // Act - var renderBatch = GetRenderedBatch(); - var componentInstance = newTree.GetFrames().AsEnumerable().First().Component as FakeComponent; - - // Assert - Assert.Equal(1, renderBatch.UpdatedComponents.Count); - var rootComponentDiff = renderBatch.UpdatedComponents.Array[0]; - AssertEdit(rootComponentDiff.Edits.Single(), RenderTreeEditType.PrependFrame, 0); - Assert.NotNull(componentInstance); - Assert.Equal(123, componentInstance.IntProperty); - Assert.Equal("some string", componentInstance.StringProperty); - Assert.Same(testObject, componentInstance.ObjectProperty); - } - - [Fact] - public void RetainsChildComponentsForExistingFrames() - { - // Arrange - oldTree.AddContent(10, "text1"); // 0: text1 - oldTree.OpenElement(11, "container"); // 1: - oldTree.OpenComponent(12); // 2: - oldTree.CloseComponent(); // - oldTree.OpenComponent(13); // 3: - oldTree.CloseComponent(); // - oldTree.CloseElement(); // - newTree.AddContent(10, "text1"); // 0: text1 - newTree.OpenElement(11, "container"); // 1: - newTree.OpenComponent(12); // 2: - newTree.CloseComponent(); // - newTree.OpenComponent(13); // 3: - newTree.CloseComponent(); // - newTree.CloseElement(); // - - using var batchBuilder = new RenderBatchBuilder(); - using var renderTreeBuilder = new RenderTreeBuilder(); - RenderTreeDiffBuilder.ComputeDiff(renderer, batchBuilder, 0, renderTreeBuilder.GetFrames(), oldTree.GetFrames()); - var originalFakeComponentInstance = oldTree.GetFrames().Array[2].Component; - var originalFakeComponent2Instance = oldTree.GetFrames().Array[3].Component; - - // Act - var (result, referenceFrames) = GetSingleUpdatedComponent(); - var newFrame1 = newTree.GetFrames().Array[2]; - var newFrame2 = newTree.GetFrames().Array[3]; - - // Assert - Assert.Empty(result.Edits); - Assert.Equal(0, newFrame1.ComponentId); - Assert.Equal(1, newFrame2.ComponentId); - Assert.Same(originalFakeComponentInstance, newFrame1.Component); - Assert.Same(originalFakeComponent2Instance, newFrame2.Component); - } - - [Fact] - public void PreservesEventHandlerIdsForRetainedEventHandlers() - { - // Arrange - Action retainedHandler = _ => { }; - oldTree.OpenElement(0, "My element"); - oldTree.AddAttribute(1, "ontest", retainedHandler); - oldTree.CloseElement(); - newTree.OpenElement(0, "My element"); - newTree.AddAttribute(1, "ontest", retainedHandler); - newTree.CloseElement(); - - // Act - var (result, referenceFrames, batchBuilder) = GetSingleUpdatedComponentWithBatch(initializeFromFrames: true); - var oldAttributeFrame = oldTree.GetFrames().Array[1]; - var newAttributeFrame = newTree.GetFrames().Array[1]; - - // Assert - Assert.Empty(result.Edits); - AssertFrame.Attribute(oldAttributeFrame, "ontest", retainedHandler); - AssertFrame.Attribute(newAttributeFrame, "ontest", retainedHandler); - Assert.NotEqual(default, oldAttributeFrame.AttributeEventHandlerId); - Assert.Equal(oldAttributeFrame.AttributeEventHandlerId, newAttributeFrame.AttributeEventHandlerId); - Assert.Empty(batchBuilder.DisposedEventHandlerIDs.AsEnumerable()); - } - - [Fact] - public void PreservesEventHandlerIdsForRetainedEventHandlers_SlowPath() - { - // Arrange - Action retainedHandler = _ => { }; - oldTree.OpenElement(0, "My element"); - oldTree.AddAttribute(0, "ontest", retainedHandler); - oldTree.CloseElement(); - newTree.OpenElement(0, "My element"); - newTree.AddAttribute(0, "another-attribute", "go down the slow path please"); - newTree.AddAttribute(0, "ontest", retainedHandler); - newTree.CloseElement(); - - // Act - var (result, referenceFrames, batchBuilder) = GetSingleUpdatedComponentWithBatch(initializeFromFrames: true); - var oldAttributeFrame = oldTree.GetFrames().Array[1]; - var newAttributeFrame = newTree.GetFrames().Array[2]; - - // Assert - Assert.Single(result.Edits); - AssertFrame.Attribute(oldAttributeFrame, "ontest", retainedHandler); - AssertFrame.Attribute(newAttributeFrame, "ontest", retainedHandler); - Assert.NotEqual(default, oldAttributeFrame.AttributeEventHandlerId); - Assert.Equal(oldAttributeFrame.AttributeEventHandlerId, newAttributeFrame.AttributeEventHandlerId); - Assert.Empty(batchBuilder.DisposedEventHandlerIDs.AsEnumerable()); - } - - [Fact] - public void SetsUpdatedParametersOnChildComponents() - { - // Arrange - var objectWillNotChange = new object(); - oldTree.OpenComponent(12); - oldTree.AddAttribute(13, nameof(FakeComponent.StringProperty), "String will change"); - oldTree.AddAttribute(14, nameof(FakeComponent.ObjectProperty), objectWillNotChange); - oldTree.CloseComponent(); - newTree.OpenComponent(12); - newTree.AddAttribute(13, nameof(FakeComponent.StringProperty), "String did change"); - newTree.AddAttribute(14, nameof(FakeComponent.ObjectProperty), objectWillNotChange); - newTree.CloseComponent(); - - using var batchBuilder = new RenderBatchBuilder(); - using var renderTree = new RenderTreeBuilder(); - RenderTreeDiffBuilder.ComputeDiff(renderer, batchBuilder, 0, renderTree.GetFrames(), oldTree.GetFrames()); - var originalComponentInstance = (FakeComponent)oldTree.GetFrames().Array[0].Component; - - // Act - var renderBatch = GetRenderedBatch(); - var newComponentInstance = (FakeComponent)oldTree.GetFrames().Array[0].Component; - - // Assert - Assert.Equal(1, renderBatch.UpdatedComponents.Count); // Because the diff builder only queues child component renders; it doesn't actually perform them itself - Assert.Same(originalComponentInstance, newComponentInstance); - Assert.Equal("String did change", newComponentInstance.StringProperty); - Assert.Same(objectWillNotChange, newComponentInstance.ObjectProperty); - } - - [Fact] - public void SkipsUpdatingParametersOnChildComponentsIfAllAreDefinitelyImmutableAndUnchanged() - { - // We only know that types are immutable if either Type.IsPrimitive, or it's one of - // a known set of common immutable types. - - // Arrange: Populate old and new with equivalent content - RenderFragment fragmentWillNotChange = builder => throw new NotImplementedException(); - var dateTimeWillNotChange = DateTime.Now; - foreach (var tree in new[] { oldTree, newTree }) - { - tree.OpenComponent(0); - tree.AddAttribute(1, "MyString", "Some fixed string"); - tree.AddAttribute(1, "MyByte", (byte)123); - tree.AddAttribute(1, "MyInt", int.MaxValue); - tree.AddAttribute(1, "MyLong", long.MaxValue); - tree.AddAttribute(1, "MyBool", true); - tree.AddAttribute(1, "MyFloat", float.MaxValue); - tree.AddAttribute(1, "MyDouble", double.MaxValue); - tree.AddAttribute(1, "MyDecimal", decimal.MinusOne); - tree.AddAttribute(1, "MyDate", dateTimeWillNotChange); - tree.CloseComponent(); - } - - using var batchBuilder = new RenderBatchBuilder(); - using var renderTreeBuilder = new RenderTreeBuilder(); - RenderTreeDiffBuilder.ComputeDiff(renderer, batchBuilder, 0, renderTreeBuilder.GetFrames(), oldTree.GetFrames()); - var originalComponentInstance = (CaptureSetParametersComponent)oldTree.GetFrames().Array[0].Component; - Assert.Equal(1, originalComponentInstance.SetParametersCallCount); - - // Act - var renderBatch = GetRenderedBatch(); - var newComponentInstance = (CaptureSetParametersComponent)oldTree.GetFrames().Array[0].Component; - - // Assert - Assert.Same(originalComponentInstance, newComponentInstance); - Assert.Equal(1, originalComponentInstance.SetParametersCallCount); // Received no further parameter change notification - } - - [Fact] - public void AlwaysRegardsRenderFragmentAsPossiblyChanged() - { - // Even if the RenderFragment instance itself is unchanged, the output you get - // when invoking it might have changed (they aren't pure functions in general) - - // Arrange: Populate old and new with equivalent content - RenderFragment fragmentWillNotChange = builder => throw new NotImplementedException(); - foreach (var tree in new[] { oldTree, newTree }) - { - tree.OpenComponent(0); - tree.AddAttribute(1, "MyFragment", fragmentWillNotChange); - tree.CloseComponent(); - } - - using var batchBuilder = new RenderBatchBuilder(); - using var renderTreeBuilder = new RenderTreeBuilder(); - RenderTreeDiffBuilder.ComputeDiff(renderer, batchBuilder, 0, renderTreeBuilder.GetFrames(), oldTree.GetFrames()); - var componentInstance = (CaptureSetParametersComponent)oldTree.GetFrames().Array[0].Component; - Assert.Equal(1, componentInstance.SetParametersCallCount); - - // Act - var renderBatch = GetRenderedBatch(); - - // Assert - Assert.Equal(2, componentInstance.SetParametersCallCount); - } - - [Fact] - public void QueuesRemovedChildComponentsForDisposal() - { - // Arrange - oldTree.OpenComponent(10); // - oldTree.CloseComponent(); // - oldTree.OpenComponent(20); // - oldTree.CloseComponent(); // - oldTree.OpenComponent(30); // - oldTree.CloseComponent(); // - newTree.OpenComponent(30); // - newTree.CloseComponent(); // - - using var batchBuilder = new RenderBatchBuilder(); - using var renderTree = new RenderTreeBuilder(); - RenderTreeDiffBuilder.ComputeDiff(renderer, batchBuilder, 0, renderTree.GetFrames(), oldTree.GetFrames()); - - // Act/Assert - // Note that we track NonDisposableComponent was disposed even though it's not IDisposable, - // because it's up to the upstream renderer to decide what "disposing" a component means - Assert.Empty(batchBuilder.ComponentDisposalQueue); - RenderTreeDiffBuilder.ComputeDiff(renderer, batchBuilder, 0, oldTree.GetFrames(), newTree.GetFrames()); - Assert.Equal(new[] { 0, 1 }, batchBuilder.ComponentDisposalQueue); - } - - [Fact] - public void AssignsDistinctIdToNewElementReferenceCaptures() - { - // Arrange - ElementReference ref1 = default, ref2 = default; - Action capture1 = val => { ref1 = val; }; - Action capture2 = val => { ref2 = val; }; - newTree.OpenElement(0, "My element"); - newTree.AddElementReferenceCapture(1, capture1); - newTree.AddElementReferenceCapture(2, capture2); - newTree.CloseElement(); - - // Act - var (diff, referenceFrames) = GetSingleUpdatedComponent(); - - // Assert: Distinct nonnull IDs - Assert.NotNull(ref1.Id); - Assert.NotNull(ref2.Id); - Assert.NotEqual(ref1.Id, ref2.Id); - - // Assert: Also specified in diff - Assert.Collection(diff.Edits, edit => - { - AssertEdit(edit, RenderTreeEditType.PrependFrame, 0); - Assert.Equal(0, edit.ReferenceFrameIndex); - }); - Assert.Collection(referenceFrames, - frame => AssertFrame.Element(frame, "My element", 3), - frame => - { - AssertFrame.ElementReferenceCapture(frame, capture1); - Assert.Equal(ref1.Id, frame.ElementReferenceCaptureId); - }, - frame => - { - AssertFrame.ElementReferenceCapture(frame, capture2); - Assert.Equal(ref2.Id, frame.ElementReferenceCaptureId); - }); - } - - [Fact] - public void PreservesIdsOnRetainedElementReferenceCaptures() - { - // Arrange - var refWriteCount = 0; - ElementReference ref1 = default; - Action capture1 = val => { ref1 = val; refWriteCount++; }; - oldTree.OpenElement(0, "My element"); - oldTree.AddElementReferenceCapture(1, capture1); - oldTree.CloseElement(); - newTree.OpenElement(0, "My element"); - newTree.AddElementReferenceCapture(1, capture1); - newTree.CloseElement(); - - // Act - var (diff, referenceFrames) = GetSingleUpdatedComponent(initializeFromFrames: true); - - // Assert: Did not invoke the capture action a second time - // Note: We're not preserving the ReferenceCaptureId on the actual RenderTreeFrames in the same - // way we do for event handler IDs, simply because there's no need to do so. We only do - // anything with ReferenceCaptureId when frames are first inserted into the document. - Assert.NotNull(ref1.Id); - Assert.Equal(1, refWriteCount); - Assert.Empty(diff.Edits); - Assert.Empty(referenceFrames); - } - - [Fact] - public void InvokesAssignerForComponentReferenceCapturesOnInsertion() - { - // Arrange - FakeComponent capturedInstance1 = null, capturedInstance2 = null; - Action assigner1 = val => { capturedInstance1 = (FakeComponent)val; }; - Action assigner2 = val => { capturedInstance2 = (FakeComponent)val; }; - newTree.OpenComponent(0); - newTree.AddComponentReferenceCapture(1, assigner1); - newTree.AddComponentReferenceCapture(2, assigner2); - newTree.CloseComponent(); - - // Act - var (diff, referenceFrames) = GetSingleUpdatedComponent(); - - // Assert: Assigned references - Assert.NotNull(capturedInstance1); - Assert.NotNull(capturedInstance2); - Assert.IsType(capturedInstance1); - Assert.IsType(capturedInstance2); - Assert.Same(capturedInstance1, capturedInstance2); - - // Assert: Also in diff, even though we have no use for it there - // (it would be costly to exclude given how the array range is copied) - Assert.Collection(diff.Edits, edit => - { - AssertEdit(edit, RenderTreeEditType.PrependFrame, 0); - Assert.Equal(0, edit.ReferenceFrameIndex); - }); - Assert.Collection(referenceFrames, - frame => - { - AssertFrame.Component(frame, 3, 0); - Assert.Same(capturedInstance1, frame.Component); - }, - frame => AssertFrame.ComponentReferenceCapture(frame, assigner1, 1), - frame => AssertFrame.ComponentReferenceCapture(frame, assigner2, 2)); - } - - [Fact] - public void DoesNotInvokeAssignerAgainForRetainedComponents() - { - // Arrange - var refWriteCount = 0; - FakeComponent capturedInstance = null; - Action assigner = val => { capturedInstance = (FakeComponent)val; refWriteCount++; }; - oldTree.OpenComponent(0); - oldTree.AddComponentReferenceCapture(1, assigner); - oldTree.CloseComponent(); - newTree.OpenComponent(0); - newTree.AddComponentReferenceCapture(1, assigner); - newTree.CloseComponent(); - - // Act - var (diff, referenceFrames) = GetSingleUpdatedComponent(initializeFromFrames: true); - - // Assert: Did not invoke the capture action a second time - Assert.NotNull(capturedInstance); - Assert.IsType(capturedInstance); - Assert.Equal(1, refWriteCount); - Assert.Empty(diff.Edits); - Assert.Empty(referenceFrames); - } - - [Fact] - public void RecognizesKeyedElementMoves() - { - // Arrange - oldTree.OpenElement(0, "container"); - oldTree.SetKey("first key"); - oldTree.AddContent(1, "First"); - oldTree.CloseElement(); - - oldTree.AddContent(2, "Unkeyed item"); - - oldTree.OpenElement(0, "container"); - oldTree.SetKey("second key"); - oldTree.AddContent(1, "Second"); - oldTree.CloseElement(); - - newTree.OpenElement(0, "container"); - newTree.SetKey("second key"); - newTree.AddContent(1, "Second"); - newTree.CloseElement(); - - newTree.AddContent(2, "Unkeyed item"); - - newTree.OpenElement(0, "container"); - newTree.SetKey("first key"); - newTree.AddContent(1, "First modified"); - newTree.CloseElement(); - - // Without the key, it changes the text contents of both - // With the key, it reorders them and just updates the text content of one - - // Act - var (result, referenceFrames) = GetSingleUpdatedComponent(); - - // Assert - Assert.Collection(result.Edits, - // First we update the modified descendants in place - entry => AssertEdit(entry, RenderTreeEditType.StepIn, 0), - entry => - { - AssertEdit(entry, RenderTreeEditType.UpdateText, 0); - Assert.Equal(0, entry.ReferenceFrameIndex); - Assert.Equal("First modified", referenceFrames[entry.ReferenceFrameIndex].TextContent); - }, - entry => AssertEdit(entry, RenderTreeEditType.StepOut, 0), - - // Then we have the permutation list - entry => AssertPermutationListEntry(entry, 0, 2), - entry => AssertPermutationListEntry(entry, 2, 0), - entry => AssertEdit(entry, RenderTreeEditType.PermutationListEnd, 0)); - } - - [Fact] - public void RecognizesKeyedComponentMoves() - { - // Arrange - oldTree.OpenComponent(0); - oldTree.SetKey("first key"); - oldTree.AddAttribute(1, nameof(FakeComponent.StringProperty), "First param"); - oldTree.CloseComponent(); - - oldTree.AddContent(2, "Unkeyed item"); - - oldTree.OpenComponent(0); - oldTree.SetKey("second key"); - oldTree.AddAttribute(1, nameof(FakeComponent.StringProperty), "Second param"); - oldTree.CloseComponent(); - - using var renderTreeBuilder = new RenderTreeBuilder(); - GetRenderedBatch(renderTreeBuilder, oldTree, false); // Assign initial IDs - var oldComponents = GetComponents(oldTree); - - newTree.OpenComponent(0); - newTree.SetKey("second key"); - newTree.AddAttribute(1, nameof(FakeComponent.StringProperty), "Second param"); - newTree.CloseComponent(); - - newTree.AddContent(2, "Unkeyed item"); - - newTree.OpenComponent(0); - newTree.SetKey("first key"); - newTree.AddAttribute(1, nameof(FakeComponent.StringProperty), "First param modified"); - newTree.CloseComponent(); - - // Without the key, it changes the parameter on both - // With the key, it reorders them and just updates the parameter of one - - // Act - var (result, referenceFrames) = GetSingleUpdatedComponent(); - var newComponents = GetComponents(newTree); - - // Assert: Retains component instances - Assert.Same(oldComponents[0], newComponents[1]); - Assert.Same(oldComponents[1], newComponents[0]); - - // Assert: Supplies updated params only to (originally) first component - Assert.Equal(2, oldComponents[0].SetParametersCallCount); - Assert.Equal(1, oldComponents[1].SetParametersCallCount); - - // Assert: Correct diff - Assert.Collection(result.Edits, - entry => AssertPermutationListEntry(entry, 0, 2), - entry => AssertPermutationListEntry(entry, 2, 0), - entry => AssertEdit(entry, RenderTreeEditType.PermutationListEnd, 0)); - } - - [Fact] - public void CanMoveBeforeInsertedItem() - { - // Arrange - AddWithKey(oldTree, "will retain"); - AddWithKey(oldTree, "will move"); - - AddWithKey(newTree, "will move"); - AddWithKey(newTree, "newly inserted"); - AddWithKey(newTree, "will retain"); - - // Act - var (result, referenceFrames) = GetSingleUpdatedComponent(); - - // Assert - Assert.Collection(result.Edits, - entry => { - AssertEdit(entry, RenderTreeEditType.PrependFrame, 1); - Assert.Equal(0, entry.ReferenceFrameIndex); - Assert.Equal("newly inserted", referenceFrames[entry.ReferenceFrameIndex].ElementKey); - }, - entry => AssertPermutationListEntry(entry, 0, 2), - entry => AssertPermutationListEntry(entry, 2, 0), - entry => AssertEdit(entry, RenderTreeEditType.PermutationListEnd, 0)); - } - - [Fact] - public void CanMoveBeforeDeletedItem() - { - // Arrange - AddWithKey(oldTree, "will retain"); - AddWithKey(oldTree, "will delete"); - AddWithKey(oldTree, "will move"); - - AddWithKey(newTree, "will move"); - AddWithKey(newTree, "will retain"); - - // Act - var (result, referenceFrames) = GetSingleUpdatedComponent(); - - // Assert - Assert.Collection(result.Edits, - entry => AssertEdit(entry, RenderTreeEditType.RemoveFrame, 1), - entry => AssertPermutationListEntry(entry, 0, 1), - entry => AssertPermutationListEntry(entry, 1, 0), - entry => AssertEdit(entry, RenderTreeEditType.PermutationListEnd, 0)); - } - - [Fact] - public void CanMoveAfterInsertedItem() - { - // Arrange - AddWithKey(oldTree, "will move"); - AddWithKey(oldTree, "will retain"); - - AddWithKey(newTree, "newly inserted"); - AddWithKey(newTree, "will retain"); - AddWithKey(newTree, "will move"); - - // Act - var (result, referenceFrames) = GetSingleUpdatedComponent(); - - // Assert - Assert.Collection(result.Edits, - entry => { - AssertEdit(entry, RenderTreeEditType.PrependFrame, 0); - Assert.Equal(0, entry.ReferenceFrameIndex); - Assert.Equal("newly inserted", referenceFrames[entry.ReferenceFrameIndex].ElementKey); - }, - entry => AssertPermutationListEntry(entry, 1, 2), - entry => AssertPermutationListEntry(entry, 2, 1), - entry => AssertEdit(entry, RenderTreeEditType.PermutationListEnd, 0)); - } - - [Fact] - public void CanMoveAfterDeletedItem() - { - // Arrange - AddWithKey(oldTree, "will move"); - AddWithKey(oldTree, "will delete"); - AddWithKey(oldTree, "will retain"); - - AddWithKey(newTree, "will retain"); - AddWithKey(newTree, "will move"); - - // Act - var (result, referenceFrames) = GetSingleUpdatedComponent(); - - // Assert - Assert.Collection(result.Edits, - entry => AssertEdit(entry, RenderTreeEditType.RemoveFrame, 1), - entry => AssertPermutationListEntry(entry, 0, 1), - entry => AssertPermutationListEntry(entry, 1, 0), - entry => AssertEdit(entry, RenderTreeEditType.PermutationListEnd, 0)); - } - - [Fact] - public void CanChangeFrameTypeWithMatchingSequenceNumber() - { - oldTree.OpenElement(0, "some elem"); - oldTree.AddContent(1, "Hello!"); - oldTree.CloseElement(); - - newTree.AddContent(0, "some text"); - - // Act - var (result, referenceFrames) = GetSingleUpdatedComponent(); - - // Assert - Assert.Collection(result.Edits, - entry => - { - AssertEdit(entry, RenderTreeEditType.PrependFrame, 0); - Assert.Equal(0, entry.ReferenceFrameIndex); - Assert.Equal("some text", referenceFrames[entry.ReferenceFrameIndex].TextContent); - }, - entry => AssertEdit(entry, RenderTreeEditType.RemoveFrame, 1)); - } - - [Fact] - public void CanChangeFrameTypeWithMatchingKey() - { - oldTree.OpenComponent(0); - oldTree.CloseComponent(); - - newTree.OpenElement(0, "some elem"); - newTree.SetKey("my key"); - newTree.CloseElement(); - - // Act - var (result, referenceFrames) = GetSingleUpdatedComponent(); - - // Assert - Assert.Collection(result.Edits, - entry => - { - AssertEdit(entry, RenderTreeEditType.PrependFrame, 0); - Assert.Equal(0, entry.ReferenceFrameIndex); - Assert.Equal("some elem", referenceFrames[entry.ReferenceFrameIndex].ElementName); - }, - entry => AssertEdit(entry, RenderTreeEditType.RemoveFrame, 1)); - } - - private (RenderTreeDiff, RenderTreeFrame[]) GetSingleUpdatedComponent(bool initializeFromFrames = false) - { - var result = GetSingleUpdatedComponentWithBatch(initializeFromFrames); - return (result.Item1, result.Item2); - } - - private (RenderTreeDiff, RenderTreeFrame[], RenderBatch) GetSingleUpdatedComponentWithBatch(bool initializeFromFrames = false) - { - var batch = GetRenderedBatch(initializeFromFrames); - var diffsInBatch = batch.UpdatedComponents; - Assert.Equal(1, diffsInBatch.Count); - return (diffsInBatch.Array[0], batch.ReferenceFrames.AsEnumerable().ToArray(), batch); - } - - private RenderBatch GetRenderedBatch(bool initializeFromFrames = false) - => GetRenderedBatch(oldTree, newTree, initializeFromFrames); - - private RenderBatch GetRenderedBatch(RenderTreeBuilder from, RenderTreeBuilder to, bool initializeFromFrames) - { - if (initializeFromFrames) - { - using var renderTreeBuilder = new RenderTreeBuilder(); - using var initializeBatchBuilder = new RenderBatchBuilder(); - - var emptyFrames = renderTreeBuilder.GetFrames(); - var oldFrames = from.GetFrames(); - - RenderTreeDiffBuilder.ComputeDiff(renderer, initializeBatchBuilder, 0, emptyFrames, oldFrames); - } - - batchBuilder?.Dispose(); - // This gets disposed as part of the test type's Dispose - batchBuilder = new RenderBatchBuilder(); - - var diff = RenderTreeDiffBuilder.ComputeDiff(renderer, batchBuilder, 0, from.GetFrames(), to.GetFrames()); - batchBuilder.UpdatedComponentDiffs.Append(diff); - return batchBuilder.ToBatch(); - } - - private static IList GetComponents(RenderTreeBuilder builder) - => GetComponents(builder); - - private static IList GetComponents(RenderTreeBuilder builder) where T : IComponent - => builder.GetFrames().AsEnumerable() - .Where(x => x.FrameType == RenderTreeFrameType.Component) - .Select(x => (T)x.Component) - .ToList(); - - private static void AddWithKey(RenderTreeBuilder builder, object key, string attributeValue = null) - { - builder.OpenElement(0, "el"); - builder.SetKey(key); - - if (attributeValue != null) - { - builder.AddAttribute(1, "attrib", attributeValue); - } - - builder.CloseElement(); - } - - private class FakeRenderer : Renderer - { - public FakeRenderer() : base(new TestServiceProvider(), NullLoggerFactory.Instance) - { - } - - public override Dispatcher Dispatcher { get; } = Dispatcher.CreateDefault(); - - protected override void HandleException(Exception exception) - => throw new NotImplementedException(); - - protected override Task UpdateDisplayAsync(in RenderBatch renderBatch) - => Task.CompletedTask; - } - - private class FakeComponent : IComponent - { - [Parameter] - public int IntProperty { get; set; } - - [Parameter] - public string StringProperty { get; set; } - - [Parameter] - public object ObjectProperty { get; set; } - - [Parameter] - public string ReadonlyProperty { get; set; } - - [Parameter] - public string PrivateProperty { get; set; } - - public string NonParameterProperty { get; set; } - - public void Attach(RenderHandle renderHandle) { } - public Task SetParametersAsync(ParameterView parameters) - { - parameters.SetParameterProperties(this); - return Task.CompletedTask; - } - } - - private class FakeComponent2 : IComponent - { - public void Attach(RenderHandle renderHandle) - { - } - - public Task SetParametersAsync(ParameterView parameters) => Task.CompletedTask; - } - - private class CaptureSetParametersComponent : IComponent - { - public int SetParametersCallCount { get; private set; } - - public void Attach(RenderHandle renderHandle) - { - } - - public Task SetParametersAsync(ParameterView parameters) - { - SetParametersCallCount++; - return Task.CompletedTask; - } - } - - private class DisposableComponent : IComponent, IDisposable - { - public int DisposalCount { get; private set; } - public void Dispose() => DisposalCount++; - - public void Attach(RenderHandle renderHandle) { } - - public Task SetParametersAsync(ParameterView parameters) => Task.CompletedTask; - } - - private class NonDisposableComponent : IComponent - { - public void Attach(RenderHandle renderHandle) { } - - public Task SetParametersAsync(ParameterView parameters) => Task.CompletedTask; - } - - private static void AssertEdit( - RenderTreeEdit edit, - RenderTreeEditType type, - int siblingIndex) - { - Assert.Equal(type, edit.Type); - Assert.Equal(siblingIndex, edit.SiblingIndex); - } - - private static void AssertPermutationListEntry( - RenderTreeEdit edit, - int fromSiblingIndex, - int toSiblingIndex) - { - Assert.Equal(RenderTreeEditType.PermutationListEntry, edit.Type); - Assert.Equal(fromSiblingIndex, edit.SiblingIndex); - Assert.Equal(toSiblingIndex, edit.MoveToSiblingIndex); - } - } -} diff --git a/src/Components/Components/test/RenderTreeUpdaterTest.cs b/src/Components/Components/test/RenderTreeUpdaterTest.cs deleted file mode 100644 index 5011d6fb4a..0000000000 --- a/src/Components/Components/test/RenderTreeUpdaterTest.cs +++ /dev/null @@ -1,167 +0,0 @@ -// 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 Microsoft.AspNetCore.Components.Rendering; -using Microsoft.AspNetCore.Components.RenderTree; -using Microsoft.AspNetCore.Components.Test.Helpers; -using Xunit; - -namespace Microsoft.AspNetCore.Components.Test -{ - public class RenderTreeUpdaterTest - { - [Fact] - public void IgnoresUnknownEventHandlerId() - { - // Arrange - var valuePropName = "testprop"; - var renderer = new TestRenderer(); - var builder = new RenderTreeBuilder(); - builder.OpenElement(0, "elem"); - builder.AddAttribute(1, "eventname", (Action)(() => { })); - builder.SetUpdatesAttributeName(valuePropName); - builder.AddAttribute(2, valuePropName, "initial value"); - builder.CloseElement(); - var frames = builder.GetFrames(); - frames.Array[1] = frames.Array[1].WithAttributeEventHandlerId(123); // An unrelated event - - // Act - RenderTreeUpdater.UpdateToMatchClientState(builder, 456, "new value"); - - // Assert - Assert.Collection(frames.AsEnumerable(), - frame => AssertFrame.Element(frame, "elem", 3, 0), - frame => AssertFrame.Attribute(frame, "eventname", v => Assert.IsType(v), 1), - frame => AssertFrame.Attribute(frame, valuePropName, "initial value", 2)); - } - - [Fact] - public void IgnoresUpdatesToAttributesIfUnexpectedValueTypeSupplied() - { - // Currently we only allow the client to supply a string or a bool, since those are the - // only types of values we render onto attributes - - // Arrange - var valuePropName = "testprop"; - var renderer = new TestRenderer(); - var builder = new RenderTreeBuilder(); - builder.OpenElement(0, "elem"); - builder.AddAttribute(1, "eventname", (Action)(() => { })); - builder.SetUpdatesAttributeName(valuePropName); - builder.AddAttribute(2, valuePropName, "initial value"); - builder.CloseElement(); - var frames = builder.GetFrames(); - frames.Array[1] = frames.Array[1].WithAttributeEventHandlerId(123); // An unrelated event - - // Act - RenderTreeUpdater.UpdateToMatchClientState(builder, 123, new object()); - - // Assert - Assert.Collection(frames.AsEnumerable(), - frame => AssertFrame.Element(frame, "elem", 3, 0), - frame => AssertFrame.Attribute(frame, "eventname", v => Assert.IsType(v), 1), - frame => AssertFrame.Attribute(frame, valuePropName, "initial value", 2)); - } - - [Fact] - public void UpdatesOnlyMatchingAttributeValue() - { - // Arrange - var valuePropName = "testprop"; - var renderer = new TestRenderer(); - var builder = new RenderTreeBuilder(); - builder.OpenElement(0, "elem"); - builder.AddAttribute(1, "eventname", (Action)(() => { })); - builder.SetUpdatesAttributeName(valuePropName); - builder.AddAttribute(2, valuePropName, "unchanged 1"); - builder.CloseElement(); - builder.OpenElement(3, "elem"); - builder.AddAttribute(4, "eventname", (Action)(() => { })); - builder.SetUpdatesAttributeName(valuePropName); - builder.AddAttribute(5, "unrelated prop before", "unchanged 2"); - builder.AddAttribute(6, valuePropName, "initial value"); - builder.AddAttribute(7, "unrelated prop after", "unchanged 3"); - builder.CloseElement(); - var frames = builder.GetFrames(); - frames.Array[1] = frames.Array[1].WithAttributeEventHandlerId(123); // An unrelated event - frames.Array[4] = frames.Array[4].WithAttributeEventHandlerId(456); - - // Act - RenderTreeUpdater.UpdateToMatchClientState(builder, 456, "new value"); - - // Assert - Assert.Collection(frames.AsEnumerable(), - frame => AssertFrame.Element(frame, "elem", 3, 0), - frame => AssertFrame.Attribute(frame, "eventname", v => Assert.IsType(v), 1), - frame => AssertFrame.Attribute(frame, valuePropName, "unchanged 1", 2), - frame => AssertFrame.Element(frame, "elem", 5, 3), - frame => AssertFrame.Attribute(frame, "eventname", v => Assert.IsType(v), 4), - frame => AssertFrame.Attribute(frame, "unrelated prop before", "unchanged 2", 5), - frame => AssertFrame.Attribute(frame, valuePropName, "new value", 6), - frame => AssertFrame.Attribute(frame, "unrelated prop after", "unchanged 3", 7)); - } - - [Fact] - public void AddsAttributeIfNotFound() - { - // Arrange - var valuePropName = "testprop"; - var renderer = new TestRenderer(); - var builder = new RenderTreeBuilder(); - builder.OpenElement(0, "elem"); - builder.AddAttribute(1, "eventname", (Action)(() => { })); - builder.SetUpdatesAttributeName(valuePropName); - builder.CloseElement(); - var frames = builder.GetFrames(); - frames.Array[1] = frames.Array[1].WithAttributeEventHandlerId(123); - - // Act - RenderTreeUpdater.UpdateToMatchClientState(builder, 123, "new value"); - frames = builder.GetFrames(); - - // Assert - Assert.Collection(frames.AsEnumerable(), - frame => AssertFrame.Element(frame, "elem", 3, 0), - frame => AssertFrame.Attribute(frame, valuePropName, "new value", RenderTreeDiffBuilder.SystemAddedAttributeSequenceNumber), - frame => AssertFrame.Attribute(frame, "eventname", v => Assert.IsType(v), 1)); - } - - [Fact] - public void ExpandsAllAncestorsWhenAddingAttribute() - { - // Arrange - var valuePropName = "testprop"; - var renderer = new TestRenderer(); - var builder = new RenderTreeBuilder(); - builder.OpenElement(0, "grandparent"); - builder.OpenRegion(1); - builder.OpenElement(2, "sibling before"); // To show that non-ancestors aren't expanded - builder.CloseElement(); - builder.OpenElement(3, "elem with handler"); - builder.AddAttribute(4, "eventname", (Action)(() => { })); - builder.SetUpdatesAttributeName(valuePropName); - builder.CloseElement(); // elem with handler - builder.CloseRegion(); - builder.CloseElement(); // grandparent - var frames = builder.GetFrames(); - frames.Array[4] = frames.Array[4].WithAttributeEventHandlerId(123); - - // Act - RenderTreeUpdater.UpdateToMatchClientState(builder, 123, "new value"); - frames = builder.GetFrames(); - - // Assert - Assert.Collection(frames.AsEnumerable(), - frame => AssertFrame.Element(frame, "grandparent", 6, 0), - frame => AssertFrame.Region(frame, 5, 1), - frame => AssertFrame.Element(frame, "sibling before", 1, 2), - frame => AssertFrame.Element(frame, "elem with handler", 3, 3), - frame => AssertFrame.Attribute(frame, valuePropName, "new value", RenderTreeDiffBuilder.SystemAddedAttributeSequenceNumber), - frame => AssertFrame.Attribute(frame, "eventname", v => Assert.IsType(v), 4)); - } - - private static ArrayRange BuildFrames(params RenderTreeFrame[] frames) - => new ArrayRange(frames, frames.Length); - } -} diff --git a/src/Components/Components/test/RendererTest.cs b/src/Components/Components/test/RendererTest.cs deleted file mode 100644 index d0e2affea2..0000000000 --- a/src/Components/Components/test/RendererTest.cs +++ /dev/null @@ -1,4500 +0,0 @@ -// 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.Collections.Concurrent; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Runtime.ExceptionServices; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Components.Rendering; -using Microsoft.AspNetCore.Components.RenderTree; -using Microsoft.AspNetCore.Components.Test.Helpers; -using Microsoft.AspNetCore.Testing; -using Microsoft.Extensions.Logging.Abstractions; -using Xunit; - -namespace Microsoft.AspNetCore.Components.Test -{ - public class RendererTest - { - // Nothing should exceed the timeout in a successful run of the the tests, this is just here to catch - // failures. - private static readonly TimeSpan Timeout = Debugger.IsAttached ? System.Threading.Timeout.InfiniteTimeSpan : TimeSpan.FromSeconds(10); - - private const string EventActionsName = nameof(NestedAsyncComponent.EventActions); - private const string WhatToRenderName = nameof(NestedAsyncComponent.WhatToRender); - private const string LogName = nameof(NestedAsyncComponent.Log); - - [Fact] - public void CanRenderTopLevelComponents() - { - // Arrange - var renderer = new TestRenderer(); - var component = new TestComponent(builder => - { - builder.OpenElement(0, "my element"); - builder.AddContent(1, "some text"); - builder.CloseElement(); - }); - - // Act - var componentId = renderer.AssignRootComponentId(component); - component.TriggerRender(); - - // Assert - var batch = renderer.Batches.Single(); - var diff = batch.DiffsByComponentId[componentId].Single(); - Assert.Collection(diff.Edits, - edit => - { - Assert.Equal(RenderTreeEditType.PrependFrame, edit.Type); - Assert.Equal(0, edit.ReferenceFrameIndex); - }); - AssertFrame.Element(batch.ReferenceFrames[0], "my element", 2); - AssertFrame.Text(batch.ReferenceFrames[1], "some text"); - } - - [Fact] - public void CanRenderNestedComponents() - { - // Arrange - var renderer = new TestRenderer(); - var component = new TestComponent(builder => - { - builder.AddContent(0, "Hello"); - builder.OpenComponent(1); - builder.AddAttribute(2, nameof(MessageComponent.Message), "Nested component output"); - builder.CloseComponent(); - }); - - // Act/Assert - var componentId = renderer.AssignRootComponentId(component); - component.TriggerRender(); - var batch = renderer.Batches.Single(); - var componentFrame = batch.ReferenceFrames - .Single(frame => frame.FrameType == RenderTreeFrameType.Component); - var nestedComponentId = componentFrame.ComponentId; - var nestedComponentDiff = batch.DiffsByComponentId[nestedComponentId].Single(); - - // We rendered both components - Assert.Equal(2, batch.DiffsByComponentId.Count); - - // The nested component exists - Assert.IsType(componentFrame.Component); - - // The nested component was rendered as part of the batch - Assert.Collection(nestedComponentDiff.Edits, - edit => - { - Assert.Equal(RenderTreeEditType.PrependFrame, edit.Type); - AssertFrame.Text( - batch.ReferenceFrames[edit.ReferenceFrameIndex], - "Nested component output"); - }); - } - - [Fact] - public void CanReRenderTopLevelComponents() - { - // Arrange - var renderer = new TestRenderer(); - var component = new MessageComponent { Message = "Initial message" }; - var componentId = renderer.AssignRootComponentId(component); - - // Act/Assert: first render - component.TriggerRender(); - var batch = renderer.Batches.Single(); - var firstDiff = batch.DiffsByComponentId[componentId].Single(); - Assert.Collection(firstDiff.Edits, - edit => - { - Assert.Equal(RenderTreeEditType.PrependFrame, edit.Type); - Assert.Equal(0, edit.ReferenceFrameIndex); - AssertFrame.Text(batch.ReferenceFrames[0], "Initial message"); - }); - - // Act/Assert: second render - component.Message = "Modified message"; - component.TriggerRender(); - var secondBatch = renderer.Batches.Skip(1).Single(); - var secondDiff = secondBatch.DiffsByComponentId[componentId].Single(); - Assert.Collection(secondDiff.Edits, - edit => - { - Assert.Equal(RenderTreeEditType.UpdateText, edit.Type); - Assert.Equal(0, edit.ReferenceFrameIndex); - AssertFrame.Text(secondBatch.ReferenceFrames[0], "Modified message"); - }); - } - - [Fact] - public void CanReRenderNestedComponents() - { - // Arrange: parent component already rendered - var renderer = new TestRenderer(); - var parentComponent = new TestComponent(builder => - { - builder.OpenComponent(0); - builder.CloseComponent(); - }); - var parentComponentId = renderer.AssignRootComponentId(parentComponent); - parentComponent.TriggerRender(); - var nestedComponentFrame = renderer.Batches.Single() - .ReferenceFrames - .Single(frame => frame.FrameType == RenderTreeFrameType.Component); - var nestedComponent = (MessageComponent)nestedComponentFrame.Component; - var nestedComponentId = nestedComponentFrame.ComponentId; - - // Assert: initial render - nestedComponent.Message = "Render 1"; - nestedComponent.TriggerRender(); - var batch = renderer.Batches[1]; - var firstDiff = batch.DiffsByComponentId[nestedComponentId].Single(); - Assert.Collection(firstDiff.Edits, - edit => - { - Assert.Equal(RenderTreeEditType.UpdateText, edit.Type); - Assert.Equal(0, edit.ReferenceFrameIndex); - AssertFrame.Text(batch.ReferenceFrames[0], "Render 1"); - }); - - // Act/Assert: re-render - nestedComponent.Message = "Render 2"; - nestedComponent.TriggerRender(); - var secondBatch = renderer.Batches[2]; - var secondDiff = secondBatch.DiffsByComponentId[nestedComponentId].Single(); - Assert.Collection(secondDiff.Edits, - edit => - { - Assert.Equal(RenderTreeEditType.UpdateText, edit.Type); - Assert.Equal(0, edit.ReferenceFrameIndex); - AssertFrame.Text(secondBatch.ReferenceFrames[0], "Render 2"); - }); - } - - [Fact] - public async Task CanRenderAsyncTopLevelComponents() - { - // Arrange - var renderer = new TestRenderer(); - var tcs = new TaskCompletionSource(); - var component = new AsyncComponent(tcs.Task, 5); // Triggers n renders, the first one creating

n

and the n-1 renders asynchronously update the value. - - // Act - var componentId = renderer.AssignRootComponentId(component); - var renderTask = renderer.Dispatcher.InvokeAsync(() => renderer.RenderRootComponentAsync(componentId)); - - // Assert - Assert.False(renderTask.IsCompleted); - tcs.SetResult(0); - await renderTask; - Assert.Equal(5, renderer.Batches.Count); - - // First render - var create = renderer.Batches[0]; - var diff = create.DiffsByComponentId[componentId].Single(); - Assert.Collection(diff.Edits, - edit => - { - Assert.Equal(RenderTreeEditType.PrependFrame, edit.Type); - Assert.Equal(0, edit.ReferenceFrameIndex); - }); - AssertFrame.Element(create.ReferenceFrames[0], "p", 2); - AssertFrame.Text(create.ReferenceFrames[1], "5"); - - // Second render - for (var i = 1; i < 5; i++) - { - - var update = renderer.Batches[i]; - var updateDiff = update.DiffsByComponentId[componentId].Single(); - Assert.Collection(updateDiff.Edits, - edit => - { - Assert.Equal(RenderTreeEditType.StepIn, edit.Type); - }, - edit => - { - Assert.Equal(RenderTreeEditType.UpdateText, edit.Type); - }, - edit => - { - Assert.Equal(RenderTreeEditType.StepOut, edit.Type); - }); - AssertFrame.Text(update.ReferenceFrames[0], (5 - i).ToString()); - } - } - - [Fact] - public async Task CanRenderAsyncNestedComponents() - { - // Arrange - var renderer = new TestRenderer(); - var component = new NestedAsyncComponent(); - - // Act/Assert - var componentId = renderer.AssignRootComponentId(component); - var log = new ConcurrentQueue<(int id, NestedAsyncComponent.EventType @event)>(); - await renderer.Dispatcher.InvokeAsync(() => renderer.RenderRootComponentAsync(componentId, ParameterView.FromDictionary(new Dictionary - { - [EventActionsName] = new Dictionary> - { - [0] = new List - { - NestedAsyncComponent.ExecutionAction.On(0, NestedAsyncComponent.EventType.OnInit), - NestedAsyncComponent.ExecutionAction.On(0, NestedAsyncComponent.EventType.OnInitAsyncAsync, async:true), - NestedAsyncComponent.ExecutionAction.On(0, NestedAsyncComponent.EventType.OnParametersSet), - NestedAsyncComponent.ExecutionAction.On(0, NestedAsyncComponent.EventType.OnParametersSetAsyncAsync, async: true), - }, - [1] = new List - { - NestedAsyncComponent.ExecutionAction.On(1, NestedAsyncComponent.EventType.OnInit), - NestedAsyncComponent.ExecutionAction.On(1, NestedAsyncComponent.EventType.OnInitAsyncAsync, async:true), - NestedAsyncComponent.ExecutionAction.On(1, NestedAsyncComponent.EventType.OnParametersSet), - NestedAsyncComponent.ExecutionAction.On(1, NestedAsyncComponent.EventType.OnParametersSetAsyncAsync, async: true), - } - }, - [WhatToRenderName] = new Dictionary> - { - [0] = CreateRenderFactory(new[] { 1 }), - [1] = CreateRenderFactory(Array.Empty()) - }, - [LogName] = log - }))); - - var logForParent = log.Where(l => l.id == 0).ToArray(); - var logForChild = log.Where(l => l.id == 1).ToArray(); - - AssertStream(0, logForParent); - AssertStream(1, logForChild); - } - - [Fact] - public async Task CanRenderAsyncComponentsWithSyncChildComponents() - { - // Arrange - var renderer = new TestRenderer(); - var component = new NestedAsyncComponent(); - - // Act/Assert - var componentId = renderer.AssignRootComponentId(component); - var log = new ConcurrentQueue<(int id, NestedAsyncComponent.EventType @event)>(); - await renderer.Dispatcher.InvokeAsync(() => renderer.RenderRootComponentAsync(componentId, ParameterView.FromDictionary(new Dictionary - { - [EventActionsName] = new Dictionary> - { - [0] = new List - { - NestedAsyncComponent.ExecutionAction.On(0, NestedAsyncComponent.EventType.OnInit), - NestedAsyncComponent.ExecutionAction.On(0, NestedAsyncComponent.EventType.OnInitAsyncAsync, async:true), - NestedAsyncComponent.ExecutionAction.On(0, NestedAsyncComponent.EventType.OnParametersSet), - NestedAsyncComponent.ExecutionAction.On(0, NestedAsyncComponent.EventType.OnParametersSetAsyncAsync, async: true), - }, - [1] = new List - { - NestedAsyncComponent.ExecutionAction.On(1, NestedAsyncComponent.EventType.OnInit), - NestedAsyncComponent.ExecutionAction.On(1, NestedAsyncComponent.EventType.OnInitAsyncAsync), - NestedAsyncComponent.ExecutionAction.On(1, NestedAsyncComponent.EventType.OnParametersSet), - NestedAsyncComponent.ExecutionAction.On(1, NestedAsyncComponent.EventType.OnParametersSetAsyncAsync), - } - }, - [WhatToRenderName] = new Dictionary> - { - [0] = CreateRenderFactory(new[] { 1 }), - [1] = CreateRenderFactory(Array.Empty()) - }, - [LogName] = log - }))); - - var logForParent = log.Where(l => l.id == 0).ToArray(); - var logForChild = log.Where(l => l.id == 1).ToArray(); - - AssertStream(0, logForParent); - AssertStream(1, logForChild); - } - - [Fact] - public async Task CanRenderAsyncComponentsWithAsyncChildInit() - { - // Arrange - var renderer = new TestRenderer(); - var component = new NestedAsyncComponent(); - - // Act/Assert - var componentId = renderer.AssignRootComponentId(component); - var log = new ConcurrentQueue<(int id, NestedAsyncComponent.EventType @event)>(); - await renderer.Dispatcher.InvokeAsync(() => renderer.RenderRootComponentAsync(componentId, ParameterView.FromDictionary(new Dictionary - { - [EventActionsName] = new Dictionary> - { - [0] = new List - { - NestedAsyncComponent.ExecutionAction.On(0, NestedAsyncComponent.EventType.OnInit), - NestedAsyncComponent.ExecutionAction.On(0, NestedAsyncComponent.EventType.OnInitAsyncAsync, async:true), - NestedAsyncComponent.ExecutionAction.On(0, NestedAsyncComponent.EventType.OnParametersSet), - NestedAsyncComponent.ExecutionAction.On(0, NestedAsyncComponent.EventType.OnParametersSetAsyncAsync, async: true), - }, - [1] = new List - { - NestedAsyncComponent.ExecutionAction.On(1, NestedAsyncComponent.EventType.OnInit), - NestedAsyncComponent.ExecutionAction.On(1, NestedAsyncComponent.EventType.OnInitAsyncAsync, async:true), - NestedAsyncComponent.ExecutionAction.On(1, NestedAsyncComponent.EventType.OnParametersSet), - NestedAsyncComponent.ExecutionAction.On(1, NestedAsyncComponent.EventType.OnParametersSetAsyncAsync), - } - }, - [WhatToRenderName] = new Dictionary> - { - [0] = CreateRenderFactory(new[] { 1 }), - [1] = CreateRenderFactory(Array.Empty()) - }, - [LogName] = log - }))); - - var logForParent = log.Where(l => l.id == 0).ToArray(); - var logForChild = log.Where(l => l.id == 1).ToArray(); - - AssertStream(0, logForParent); - AssertStream(1, logForChild); - } - - [Fact] - public async Task CanRenderAsyncComponentsWithMultipleAsyncChildren() - { - // Arrange - var renderer = new TestRenderer(); - var component = new NestedAsyncComponent(); - - // Act/Assert - var componentId = renderer.AssignRootComponentId(component); - var log = new ConcurrentQueue<(int id, NestedAsyncComponent.EventType @event)>(); - await renderer.Dispatcher.InvokeAsync(() => renderer.RenderRootComponentAsync(componentId, ParameterView.FromDictionary(new Dictionary - { - [EventActionsName] = new Dictionary> - { - [0] = new List - { - NestedAsyncComponent.ExecutionAction.On(0, NestedAsyncComponent.EventType.OnInit), - NestedAsyncComponent.ExecutionAction.On(0, NestedAsyncComponent.EventType.OnInitAsyncAsync, async:true), - NestedAsyncComponent.ExecutionAction.On(0, NestedAsyncComponent.EventType.OnParametersSet), - NestedAsyncComponent.ExecutionAction.On(0, NestedAsyncComponent.EventType.OnParametersSetAsyncAsync, async: true), - }, - [1] = new List - { - NestedAsyncComponent.ExecutionAction.On(1, NestedAsyncComponent.EventType.OnInit), - NestedAsyncComponent.ExecutionAction.On(1, NestedAsyncComponent.EventType.OnInitAsyncAsync, async:true), - NestedAsyncComponent.ExecutionAction.On(1, NestedAsyncComponent.EventType.OnParametersSet), - NestedAsyncComponent.ExecutionAction.On(1, NestedAsyncComponent.EventType.OnParametersSetAsyncAsync, async:true), - }, - [2] = new List - { - NestedAsyncComponent.ExecutionAction.On(2, NestedAsyncComponent.EventType.OnInit), - NestedAsyncComponent.ExecutionAction.On(2, NestedAsyncComponent.EventType.OnInitAsyncAsync, async:true), - NestedAsyncComponent.ExecutionAction.On(2, NestedAsyncComponent.EventType.OnParametersSet), - NestedAsyncComponent.ExecutionAction.On(2, NestedAsyncComponent.EventType.OnParametersSetAsyncAsync, async:true), - }, - [3] = new List - { - NestedAsyncComponent.ExecutionAction.On(3, NestedAsyncComponent.EventType.OnInit), - NestedAsyncComponent.ExecutionAction.On(3, NestedAsyncComponent.EventType.OnInitAsyncAsync, async:true), - NestedAsyncComponent.ExecutionAction.On(3, NestedAsyncComponent.EventType.OnParametersSet), - NestedAsyncComponent.ExecutionAction.On(3, NestedAsyncComponent.EventType.OnParametersSetAsyncAsync, async:true), - } - }, - [WhatToRenderName] = new Dictionary> - { - [0] = CreateRenderFactory(new[] { 1, 2 }), - [1] = CreateRenderFactory(new[] { 3 }), - [2] = CreateRenderFactory(Array.Empty()), - [3] = CreateRenderFactory(Array.Empty()) - }, - [LogName] = log - }))); - - var logForParent = log.Where(l => l.id == 0).ToArray(); - var logForFirstChild = log.Where(l => l.id == 1).ToArray(); - var logForSecondChild = log.Where(l => l.id == 2).ToArray(); - var logForThirdChild = log.Where(l => l.id == 3).ToArray(); - - AssertStream(0, logForParent); - AssertStream(1, logForFirstChild); - AssertStream(2, logForSecondChild); - AssertStream(3, logForThirdChild); - } - - [Fact] - public void DispatchingEventsWithoutAsyncWorkShouldCompleteSynchronously() - { - // Arrange: Render a component with an event handler - var renderer = new TestRenderer(); - EventArgs receivedArgs = null; - - var component = new EventComponent - { - OnTest = args => { receivedArgs = args; } - }; - var componentId = renderer.AssignRootComponentId(component); - component.TriggerRender(); - - var eventHandlerId = renderer.Batches.Single() - .ReferenceFrames - .First(frame => frame.AttributeValue != null) - .AttributeEventHandlerId; - - // Assert: Event not yet fired - Assert.Null(receivedArgs); - - // Act/Assert: Event can be fired - var eventArgs = new EventArgs(); - var task = renderer.DispatchEventAsync(eventHandlerId, eventArgs); - - // This should always be run synchronously - Assert.True(task.IsCompletedSuccessfully); - } - - [Fact] - public void CanDispatchEventsToTopLevelComponents() - { - // Arrange: Render a component with an event handler - var renderer = new TestRenderer(); - EventArgs receivedArgs = null; - - var component = new EventComponent - { - OnTest = args => { receivedArgs = args; } - }; - var componentId = renderer.AssignRootComponentId(component); - component.TriggerRender(); - - var eventHandlerId = renderer.Batches.Single() - .ReferenceFrames - .First(frame => frame.AttributeValue != null) - .AttributeEventHandlerId; - - // Assert: Event not yet fired - Assert.Null(receivedArgs); - - // Act/Assert: Event can be fired - var eventArgs = new EventArgs(); - var renderTask = renderer.DispatchEventAsync(eventHandlerId, eventArgs); - Assert.True(renderTask.IsCompletedSuccessfully); - Assert.Same(eventArgs, receivedArgs); - } - - [Fact] - public void DispatchEventHandlesSynchronousExceptionsFromEventHandlers() - { - // Arrange: Render a component with an event handler - var renderer = new TestRenderer { - ShouldHandleExceptions = true - }; - - var component = new EventComponent - { - OnTest = args => throw new Exception("Error") - }; - var componentId = renderer.AssignRootComponentId(component); - component.TriggerRender(); - - var eventHandlerId = renderer.Batches.Single() - .ReferenceFrames - .First(frame => frame.AttributeValue != null) - .AttributeEventHandlerId; - - // Assert: Event not yet fired - Assert.Empty(renderer.HandledExceptions); - - // Act/Assert: Event can be fired - var eventArgs = new EventArgs(); - var renderTask = renderer.DispatchEventAsync(eventHandlerId, eventArgs); - Assert.True(renderTask.IsCompletedSuccessfully); - - var exception = Assert.Single(renderer.HandledExceptions); - Assert.Equal("Error", exception.Message); - } - - [Fact] - public void CanDispatchTypedEventsToTopLevelComponents() - { - // Arrange: Render a component with an event handler - var renderer = new TestRenderer(); - DerivedEventArgs receivedArgs = null; - - var component = new EventComponent - { - OnClick = args => { receivedArgs = args; } - }; - var componentId = renderer.AssignRootComponentId(component); - component.TriggerRender(); - - var eventHandlerId = renderer.Batches.Single() - .ReferenceFrames - .First(frame => frame.AttributeValue != null) - .AttributeEventHandlerId; - - // Assert: Event not yet fired - Assert.Null(receivedArgs); - - // Act/Assert: Event can be fired - var eventArgs = new DerivedEventArgs(); - var renderTask = renderer.DispatchEventAsync(eventHandlerId, eventArgs); - Assert.True(renderTask.IsCompletedSuccessfully); - Assert.Same(eventArgs, receivedArgs); - } - - [Fact] - public void CanDispatchActionEventsToTopLevelComponents() - { - // Arrange: Render a component with an event handler - var renderer = new TestRenderer(); - object receivedArgs = null; - - var component = new EventComponent - { - OnClickAction = () => { receivedArgs = new object(); } - }; - var componentId = renderer.AssignRootComponentId(component); - component.TriggerRender(); - - var eventHandlerId = renderer.Batches.Single() - .ReferenceFrames - .First(frame => frame.AttributeValue != null) - .AttributeEventHandlerId; - - // Assert: Event not yet fired - Assert.Null(receivedArgs); - - // Act/Assert: Event can be fired - var eventArgs = new DerivedEventArgs(); - var renderTask = renderer.DispatchEventAsync(eventHandlerId, eventArgs); - Assert.True(renderTask.IsCompletedSuccessfully); - Assert.NotNull(receivedArgs); - } - - [Fact] - public void CanDispatchEventsToNestedComponents() - { - EventArgs receivedArgs = null; - - // Arrange: Render parent component - var renderer = new TestRenderer(); - var parentComponent = new TestComponent(builder => - { - builder.OpenComponent(0); - builder.CloseComponent(); - }); - var parentComponentId = renderer.AssignRootComponentId(parentComponent); - parentComponent.TriggerRender(); - - // Arrange: Render nested component - var nestedComponentFrame = renderer.Batches.Single() - .ReferenceFrames - .Single(frame => frame.FrameType == RenderTreeFrameType.Component); - var nestedComponent = (EventComponent)nestedComponentFrame.Component; - nestedComponent.OnTest = args => { receivedArgs = args; }; - var nestedComponentId = nestedComponentFrame.ComponentId; - nestedComponent.TriggerRender(); - - // Find nested component's event handler ID - var eventHandlerId = renderer.Batches[1] - .ReferenceFrames - .First(frame => frame.AttributeValue != null) - .AttributeEventHandlerId; - - // Assert: Event not yet fired - Assert.Null(receivedArgs); - - // Act/Assert: Event can be fired - var eventArgs = new EventArgs(); - var renderTask = renderer.DispatchEventAsync(eventHandlerId, eventArgs); - Assert.True(renderTask.IsCompletedSuccessfully); - Assert.Same(eventArgs, receivedArgs); - } - - [Fact] - public async Task CanAsyncDispatchEventsToTopLevelComponents() - { - // Arrange: Render a component with an event handler - var renderer = new TestRenderer(); - EventArgs receivedArgs = null; - - var state = 0; - var tcs = new TaskCompletionSource(); - - var component = new EventComponent - { - OnTestAsync = async (args) => - { - receivedArgs = args; - state = 1; - await tcs.Task; - state = 2; - }, - }; - var componentId = renderer.AssignRootComponentId(component); - component.TriggerRender(); - - var eventHandlerId = renderer.Batches.Single() - .ReferenceFrames - .First(frame => frame.AttributeValue != null) - .AttributeEventHandlerId; - - // Assert: Event not yet fired - Assert.Null(receivedArgs); - - // Act/Assert: Event can be fired - var eventArgs = new EventArgs(); - var task = renderer.DispatchEventAsync(eventHandlerId, eventArgs); - Assert.Equal(1, state); - Assert.Same(eventArgs, receivedArgs); - - tcs.SetResult(null); - await task; - - Assert.Equal(2, state); - } - - [Fact] - public async Task CanAsyncDispatchTypedEventsToTopLevelComponents() - { - // Arrange: Render a component with an event handler - var renderer = new TestRenderer(); - DerivedEventArgs receivedArgs = null; - - var state = 0; - var tcs = new TaskCompletionSource(); - - var component = new EventComponent - { - OnClickAsync = async (args) => - { - receivedArgs = args; - state = 1; - await tcs.Task; - state = 2; - } - }; - var componentId = renderer.AssignRootComponentId(component); - component.TriggerRender(); - - var eventHandlerId = renderer.Batches.Single() - .ReferenceFrames - .First(frame => frame.AttributeValue != null) - .AttributeEventHandlerId; - - // Assert: Event not yet fired - Assert.Null(receivedArgs); - - // Act/Assert: Event can be fired - var eventArgs = new DerivedEventArgs(); - var task = renderer.DispatchEventAsync(eventHandlerId, eventArgs); - Assert.Equal(1, state); - Assert.Same(eventArgs, receivedArgs); - - tcs.SetResult(null); - await task; - - Assert.Equal(2, state); - } - - [Fact] - public async Task CanAsyncDispatchActionEventsToTopLevelComponents() - { - // Arrange: Render a component with an event handler - var renderer = new TestRenderer(); - object receivedArgs = null; - - var state = 0; - var tcs = new TaskCompletionSource(); - - var component = new EventComponent - { - OnClickAsyncAction = async () => - { - receivedArgs = new object(); - state = 1; - await tcs.Task; - state = 2; - } - }; - var componentId = renderer.AssignRootComponentId(component); - component.TriggerRender(); - - var eventHandlerId = renderer.Batches.Single() - .ReferenceFrames - .First(frame => frame.AttributeValue != null) - .AttributeEventHandlerId; - - // Assert: Event not yet fired - Assert.Null(receivedArgs); - - // Act/Assert: Event can be fired - var eventArgs = new DerivedEventArgs(); - var task = renderer.DispatchEventAsync(eventHandlerId, eventArgs); - Assert.Equal(1, state); - Assert.NotNull(receivedArgs); - - tcs.SetResult(null); - await task; - - Assert.Equal(2, state); - } - - [Fact] - public async Task CanAsyncDispatchEventsToNestedComponents() - { - EventArgs receivedArgs = null; - - var state = 0; - var tcs = new TaskCompletionSource(); - - // Arrange: Render parent component - var renderer = new TestRenderer(); - var parentComponent = new TestComponent(builder => - { - builder.OpenComponent(0); - builder.CloseComponent(); - }); - var parentComponentId = renderer.AssignRootComponentId(parentComponent); - parentComponent.TriggerRender(); - - // Arrange: Render nested component - var nestedComponentFrame = renderer.Batches.Single() - .ReferenceFrames - .Single(frame => frame.FrameType == RenderTreeFrameType.Component); - var nestedComponent = (EventComponent)nestedComponentFrame.Component; - nestedComponent.OnTestAsync = async (args) => - { - receivedArgs = args; - state = 1; - await tcs.Task; - state = 2; - }; - var nestedComponentId = nestedComponentFrame.ComponentId; - nestedComponent.TriggerRender(); - - // Find nested component's event handler ID - var eventHandlerId = renderer.Batches[1] - .ReferenceFrames - .First(frame => frame.AttributeValue != null) - .AttributeEventHandlerId; - - // Assert: Event not yet fired - Assert.Null(receivedArgs); - - // Act/Assert: Event can be fired - var eventArgs = new EventArgs(); - var task = renderer.DispatchEventAsync(eventHandlerId, eventArgs); - Assert.Equal(1, state); - Assert.Same(eventArgs, receivedArgs); - - tcs.SetResult(null); - await task; - - Assert.Equal(2, state); - } - - // This tests the behaviour of dispatching an event when the event-handler - // delegate is a bound-delegate with a target that points to the parent component. - // - // This is a very common case when a component accepts a delegate parameter that - // will be hooked up to a DOM event handler. It's essential that this will dispatch - // to the parent component so that manual StateHasChanged calls are not necessary. - [Fact] - public async Task EventDispatching_DelegateParameter_MethodToDelegateConversion() - { - // Arrange - var outerStateChangeCount = 0; - - var renderer = new TestRenderer(); - var parentComponent = new OuterEventComponent(); - parentComponent.RenderFragment = (builder) => - { - builder.OpenComponent(0); - builder.AddAttribute(1, nameof(EventComponent.OnClickAction), (Action)parentComponent.SomeMethod); - builder.CloseComponent(); - }; - parentComponent.OnEvent = () => - { - outerStateChangeCount++; - }; - - var parentComponentId = renderer.AssignRootComponentId(parentComponent); - await parentComponent.TriggerRenderAsync(); - - var eventHandlerId = renderer.Batches[0] - .ReferenceFrames - .First(frame => frame.AttributeName == "onclickaction") - .AttributeEventHandlerId; - - // Act - var eventArgs = new DerivedEventArgs(); - await renderer.DispatchEventAsync(eventHandlerId, eventArgs); - - // Assert - Assert.Equal(1, parentComponent.SomeMethodCallCount); - Assert.Equal(1, outerStateChangeCount); - } - - // This is the inverse case of EventDispatching_DelegateParameter_MethodToDelegateConversion - // where the event-handling delegate has a target that is not a component. - // - // This is a degenerate case that we don't expect to occur in applications often, - // but it's important to verify the semantics. - [Fact] - public async Task EventDispatching_DelegateParameter_NoTargetLambda() - { - // Arrange - var outerStateChangeCount = 0; - - var renderer = new TestRenderer(); - var parentComponent = new OuterEventComponent(); - parentComponent.RenderFragment = (builder) => - { - builder.OpenComponent(0); - builder.AddAttribute(1, nameof(EventComponent.OnClickAction), (Action)(() => - { - parentComponent.SomeMethod(); - })); - builder.CloseComponent(); - }; - parentComponent.OnEvent = () => - { - outerStateChangeCount++; - }; - - var parentComponentId = renderer.AssignRootComponentId(parentComponent); - await parentComponent.TriggerRenderAsync(); - - var eventHandlerId = renderer.Batches[0] - .ReferenceFrames - .First(frame => frame.AttributeName == "onclickaction") - .AttributeEventHandlerId; - - // Act - var eventArgs = new DerivedEventArgs(); - await renderer.DispatchEventAsync(eventHandlerId, eventArgs); - - // Assert - Assert.Equal(1, parentComponent.SomeMethodCallCount); - Assert.Equal(0, outerStateChangeCount); - } - - // This is a similar case to EventDispatching_DelegateParameter_MethodToDelegateConversion - // but uses our event handling infrastructure to achieve the same effect. The call to CreateDelegate - // is not necessary for correctness in this case - it should just no op. - [Fact] - public async Task EventDispatching_EventCallback_MethodToDelegateConversion() - { - // Arrange - var outerStateChangeCount = 0; - - var renderer = new TestRenderer(); - var parentComponent = new OuterEventComponent(); - parentComponent.RenderFragment = (builder) => - { - builder.OpenComponent(0); - builder.AddAttribute(1, nameof(EventComponent.OnClickEventCallback), EventCallback.Factory.Create(parentComponent, (Action)parentComponent.SomeMethod)); - builder.CloseComponent(); - }; - parentComponent.OnEvent = () => - { - outerStateChangeCount++; - }; - - var parentComponentId = renderer.AssignRootComponentId(parentComponent); - await parentComponent.TriggerRenderAsync(); - - var eventHandlerId = renderer.Batches[0] - .ReferenceFrames - .First(frame => frame.AttributeName == "onclick") - .AttributeEventHandlerId; - - // Act - var eventArgs = new DerivedEventArgs(); - await renderer.DispatchEventAsync(eventHandlerId, eventArgs); - - // Assert - Assert.Equal(1, parentComponent.SomeMethodCallCount); - Assert.Equal(1, outerStateChangeCount); - } - - // This is a similar case to EventDispatching_DelegateParameter_NoTargetLambda but it uses - // our event-handling infrastructure to avoid the need for a manual StateHasChanged() - [Fact] - public async Task EventDispatching_EventCallback_NoTargetLambda() - { - // Arrange - var outerStateChangeCount = 0; - - var renderer = new TestRenderer(); - var parentComponent = new OuterEventComponent(); - parentComponent.RenderFragment = (builder) => - { - builder.OpenComponent(0); - builder.AddAttribute(1, nameof(EventComponent.OnClickEventCallback), EventCallback.Factory.Create(parentComponent, (Action)(() => - { - parentComponent.SomeMethod(); - }))); - builder.CloseComponent(); - }; - parentComponent.OnEvent = () => - { - outerStateChangeCount++; - }; - - var parentComponentId = renderer.AssignRootComponentId(parentComponent); - await parentComponent.TriggerRenderAsync(); - - var eventHandlerId = renderer.Batches[0] - .ReferenceFrames - .First(frame => frame.AttributeName == "onclick") - .AttributeEventHandlerId; - - // Act - var eventArgs = new DerivedEventArgs(); - await renderer.DispatchEventAsync(eventHandlerId, eventArgs); - - // Assert - Assert.Equal(1, parentComponent.SomeMethodCallCount); - Assert.Equal(1, outerStateChangeCount); - } - - // This is a similar case to EventDispatching_DelegateParameter_NoTargetLambda but it uses - // our event-handling infrastructure to avoid the need for a manual StateHasChanged() - [Fact] - public async Task EventDispatching_EventCallback_AsyncNoTargetLambda() - { - // Arrange - var outerStateChangeCount = 0; - - var renderer = new TestRenderer(); - var parentComponent = new OuterEventComponent(); - parentComponent.RenderFragment = (builder) => - { - builder.OpenComponent(0); - builder.AddAttribute(1, nameof(EventComponent.OnClickEventCallback), EventCallback.Factory.Create(parentComponent, (Func)(() => - { - parentComponent.SomeMethod(); - return Task.CompletedTask; - }))); - builder.CloseComponent(); - }; - parentComponent.OnEvent = () => - { - outerStateChangeCount++; - }; - - var parentComponentId = renderer.AssignRootComponentId(parentComponent); - await parentComponent.TriggerRenderAsync(); - - var eventHandlerId = renderer.Batches[0] - .ReferenceFrames - .First(frame => frame.AttributeName == "onclick") - .AttributeEventHandlerId; - - // Act - var eventArgs = new DerivedEventArgs(); - await renderer.DispatchEventAsync(eventHandlerId, eventArgs); - - // Assert - Assert.Equal(1, parentComponent.SomeMethodCallCount); - Assert.Equal(1, outerStateChangeCount); - } - - [Fact] - public async Task EventDispatching_EventCallbackOfT_MethodToDelegateConversion() - { - // Arrange - var outerStateChangeCount = 0; - - var renderer = new TestRenderer(); - var parentComponent = new OuterEventComponent(); - parentComponent.RenderFragment = (builder) => - { - builder.OpenComponent(0); - builder.AddAttribute(1, nameof(EventComponent.OnClickEventCallbackOfT), EventCallback.Factory.Create(parentComponent, (Action)parentComponent.SomeMethod)); - builder.CloseComponent(); - }; - parentComponent.OnEvent = () => - { - outerStateChangeCount++; - }; - - var parentComponentId = renderer.AssignRootComponentId(parentComponent); - await parentComponent.TriggerRenderAsync(); - - var eventHandlerId = renderer.Batches[0] - .ReferenceFrames - .First(frame => frame.AttributeName == "onclick") - .AttributeEventHandlerId; - - // Act - var eventArgs = new DerivedEventArgs(); - await renderer.DispatchEventAsync(eventHandlerId, eventArgs); - - // Assert - Assert.Equal(1, parentComponent.SomeMethodCallCount); - Assert.Equal(1, outerStateChangeCount); - } - - // This is a similar case to EventDispatching_DelegateParameter_NoTargetLambda but it uses - // our event-handling infrastructure to avoid the need for a manual StateHasChanged() - [Fact] - public async Task EventDispatching_EventCallbackOfT_NoTargetLambda() - { - // Arrange - var outerStateChangeCount = 0; - - var renderer = new TestRenderer(); - var parentComponent = new OuterEventComponent(); - parentComponent.RenderFragment = (builder) => - { - builder.OpenComponent(0); - builder.AddAttribute(1, nameof(EventComponent.OnClickEventCallbackOfT), EventCallback.Factory.Create(parentComponent, (Action)(() => - { - parentComponent.SomeMethod(); - }))); - builder.CloseComponent(); - }; - parentComponent.OnEvent = () => - { - outerStateChangeCount++; - }; - - var parentComponentId = renderer.AssignRootComponentId(parentComponent); - await parentComponent.TriggerRenderAsync(); - - var eventHandlerId = renderer.Batches[0] - .ReferenceFrames - .First(frame => frame.AttributeName == "onclick") - .AttributeEventHandlerId; - - // Act - var eventArgs = new DerivedEventArgs(); - await renderer.DispatchEventAsync(eventHandlerId, eventArgs); - - // Assert - Assert.Equal(1, parentComponent.SomeMethodCallCount); - Assert.Equal(1, outerStateChangeCount); - } - - // This is a similar case to EventDispatching_DelegateParameter_NoTargetLambda but it uses - // our event-handling infrastructure to avoid the need for a manual StateHasChanged() - [Fact] - public async Task EventDispatching_EventCallbackOfT_AsyncNoTargetLambda() - { - // Arrange - var outerStateChangeCount = 0; - - var renderer = new TestRenderer(); - var parentComponent = new OuterEventComponent(); - parentComponent.RenderFragment = (builder) => - { - builder.OpenComponent(0); - builder.AddAttribute(1, nameof(EventComponent.OnClickEventCallbackOfT), EventCallback.Factory.Create(parentComponent, (Func)(() => - { - parentComponent.SomeMethod(); - return Task.CompletedTask; - }))); - builder.CloseComponent(); - }; - parentComponent.OnEvent = () => - { - outerStateChangeCount++; - }; - - var parentComponentId = renderer.AssignRootComponentId(parentComponent); - await parentComponent.TriggerRenderAsync(); - - var eventHandlerId = renderer.Batches[0] - .ReferenceFrames - .First(frame => frame.AttributeName == "onclick") - .AttributeEventHandlerId; - - // Act - var eventArgs = new DerivedEventArgs(); - await renderer.DispatchEventAsync(eventHandlerId, eventArgs); - - // Assert - Assert.Equal(1, parentComponent.SomeMethodCallCount); - Assert.Equal(1, outerStateChangeCount); - } - - [Fact] - public async Task DispatchEventAsync_Delegate_SynchronousCompletion() - { - // Arrange - var renderer = new TestRenderer(); - var parentComponent = new OuterEventComponent(); - parentComponent.RenderFragment = (builder) => - { - builder.OpenComponent(0); - builder.AddAttribute(1, nameof(EventComponent.OnClickAction), (Action)(() => - { - // Do nothing. - })); - builder.CloseComponent(); - }; - - var parentComponentId = renderer.AssignRootComponentId(parentComponent); - await parentComponent.TriggerRenderAsync(); - - var eventHandlerId = renderer.Batches[0] - .ReferenceFrames - .First(frame => frame.AttributeName == "onclickaction") - .AttributeEventHandlerId; - - // Act - var task = renderer.DispatchEventAsync(eventHandlerId, new DerivedEventArgs()); - - // Assert - Assert.Equal(TaskStatus.RanToCompletion, task.Status); - await task; // Does not throw - } - - [Fact] - public async Task DispatchEventAsync_EventCallback_SynchronousCompletion() - { - // Arrange - var renderer = new TestRenderer(); - var parentComponent = new OuterEventComponent(); - parentComponent.RenderFragment = (builder) => - { - builder.OpenComponent(0); - builder.AddAttribute(1, nameof(EventComponent.OnClickEventCallback), EventCallback.Factory.Create(parentComponent, (Action)(() => - { - // Do nothing. - }))); - builder.CloseComponent(); - }; - - var parentComponentId = renderer.AssignRootComponentId(parentComponent); - await parentComponent.TriggerRenderAsync(); - - var eventHandlerId = renderer.Batches[0] - .ReferenceFrames - .First(frame => frame.AttributeName == "onclick") - .AttributeEventHandlerId; - - // Act - var task = renderer.DispatchEventAsync(eventHandlerId, new DerivedEventArgs()); - - // Assert - Assert.Equal(TaskStatus.RanToCompletion, task.Status); - await task; // Does not throw - } - - [Fact] - public async Task DispatchEventAsync_EventCallbackOfT_SynchronousCompletion() - { - // Arrange - DerivedEventArgs arg = null; - - var renderer = new TestRenderer(); - var parentComponent = new OuterEventComponent(); - parentComponent.RenderFragment = (builder) => - { - builder.OpenComponent(0); - builder.AddAttribute(1, nameof(EventComponent.OnClickEventCallbackOfT), EventCallback.Factory.Create(parentComponent, (Action)((e) => - { - arg = e; - }))); - builder.CloseComponent(); - }; - - var parentComponentId = renderer.AssignRootComponentId(parentComponent); - await parentComponent.TriggerRenderAsync(); - - var eventHandlerId = renderer.Batches[0] - .ReferenceFrames - .First(frame => frame.AttributeName == "onclick") - .AttributeEventHandlerId; - - // Act - var task = renderer.DispatchEventAsync(eventHandlerId, new DerivedEventArgs()); - - // Assert - Assert.NotNull(arg); - Assert.Equal(TaskStatus.RanToCompletion, task.Status); - await task; // Does not throw - } - - [Fact] - public async Task DispatchEventAsync_Delegate_SynchronousCancellation() - { - // Arrange - var renderer = new TestRenderer(); - var parentComponent = new OuterEventComponent(); - parentComponent.RenderFragment = (builder) => - { - builder.OpenComponent(0); - builder.AddAttribute(1, nameof(EventComponent.OnClickAction), (Action)(() => - { - throw new OperationCanceledException(); - })); - builder.CloseComponent(); - }; - - var parentComponentId = renderer.AssignRootComponentId(parentComponent); - await parentComponent.TriggerRenderAsync(); - - var eventHandlerId = renderer.Batches[0] - .ReferenceFrames - .First(frame => frame.AttributeName == "onclickaction") - .AttributeEventHandlerId; - - // Act - var task = renderer.DispatchEventAsync(eventHandlerId, new DerivedEventArgs()); - - // Assert - Assert.Equal(TaskStatus.Canceled, task.Status); - await Assert.ThrowsAsync(() => task); - } - - [Fact] - public async Task DispatchEventAsync_EventCallback_SynchronousCancellation() - { - // Arrange - var renderer = new TestRenderer(); - var parentComponent = new OuterEventComponent(); - parentComponent.RenderFragment = (builder) => - { - builder.OpenComponent(0); - builder.AddAttribute(1, nameof(EventComponent.OnClickEventCallback), EventCallback.Factory.Create(parentComponent, (Action)(() => - { - throw new OperationCanceledException(); - }))); - builder.CloseComponent(); - }; - - var parentComponentId = renderer.AssignRootComponentId(parentComponent); - await parentComponent.TriggerRenderAsync(); - - var eventHandlerId = renderer.Batches[0] - .ReferenceFrames - .First(frame => frame.AttributeName == "onclick") - .AttributeEventHandlerId; - - // Act - var task = renderer.DispatchEventAsync(eventHandlerId, new DerivedEventArgs()); - - // Assert - Assert.Equal(TaskStatus.Canceled, task.Status); - await Assert.ThrowsAsync(() => task); - } - - [Fact] - public async Task DispatchEventAsync_EventCallbackOfT_SynchronousCancellation() - { - // Arrange - DerivedEventArgs arg = null; - - var renderer = new TestRenderer(); - var parentComponent = new OuterEventComponent(); - parentComponent.RenderFragment = (builder) => - { - builder.OpenComponent(0); - builder.AddAttribute(1, nameof(EventComponent.OnClickEventCallbackOfT), EventCallback.Factory.Create(parentComponent, (Action)((e) => - { - arg = e; - throw new OperationCanceledException(); - }))); - builder.CloseComponent(); - }; - - var parentComponentId = renderer.AssignRootComponentId(parentComponent); - await parentComponent.TriggerRenderAsync(); - - var eventHandlerId = renderer.Batches[0] - .ReferenceFrames - .First(frame => frame.AttributeName == "onclick") - .AttributeEventHandlerId; - - // Act - var task = renderer.DispatchEventAsync(eventHandlerId, new DerivedEventArgs()); - - // Assert - Assert.NotNull(arg); - Assert.Equal(TaskStatus.Canceled, task.Status); - await Assert.ThrowsAsync(() => task); - } - - [Fact] - public async Task DispatchEventAsync_Delegate_SynchronousException() - { - // Arrange - var renderer = new TestRenderer(); - var parentComponent = new OuterEventComponent(); - parentComponent.RenderFragment = (builder) => - { - builder.OpenComponent(0); - builder.AddAttribute(1, nameof(EventComponent.OnClickAction), (Action)(() => - { - throw new InvalidTimeZoneException(); - })); - builder.CloseComponent(); - }; - - var parentComponentId = renderer.AssignRootComponentId(parentComponent); - await parentComponent.TriggerRenderAsync(); - - var eventHandlerId = renderer.Batches[0] - .ReferenceFrames - .First(frame => frame.AttributeName == "onclickaction") - .AttributeEventHandlerId; - - // Act - var task = renderer.DispatchEventAsync(eventHandlerId, new DerivedEventArgs()); - - // Assert - Assert.Equal(TaskStatus.Faulted, task.Status); - await Assert.ThrowsAsync(() => task); - } - - [Fact] - public async Task DispatchEventAsync_EventCallback_SynchronousException() - { - // Arrange - var renderer = new TestRenderer(); - var parentComponent = new OuterEventComponent(); - parentComponent.RenderFragment = (builder) => - { - builder.OpenComponent(0); - builder.AddAttribute(1, nameof(EventComponent.OnClickEventCallback), EventCallback.Factory.Create(parentComponent, (Action)(() => - { - throw new InvalidTimeZoneException(); - }))); - builder.CloseComponent(); - }; - - var parentComponentId = renderer.AssignRootComponentId(parentComponent); - await parentComponent.TriggerRenderAsync(); - - var eventHandlerId = renderer.Batches[0] - .ReferenceFrames - .First(frame => frame.AttributeName == "onclick") - .AttributeEventHandlerId; - - // Act - var task = renderer.DispatchEventAsync(eventHandlerId, new DerivedEventArgs()); - - // Assert - Assert.Equal(TaskStatus.Faulted, task.Status); - await Assert.ThrowsAsync(() => task); - } - - [Fact] - public async Task DispatchEventAsync_EventCallbackOfT_SynchronousException() - { - // Arrange - DerivedEventArgs arg = null; - - var renderer = new TestRenderer(); - var parentComponent = new OuterEventComponent(); - parentComponent.RenderFragment = (builder) => - { - builder.OpenComponent(0); - builder.AddAttribute(1, nameof(EventComponent.OnClickEventCallbackOfT), EventCallback.Factory.Create(parentComponent, (Action)((e) => - { - arg = e; - throw new InvalidTimeZoneException(); - }))); - builder.CloseComponent(); - }; - - var parentComponentId = renderer.AssignRootComponentId(parentComponent); - await parentComponent.TriggerRenderAsync(); - - var eventHandlerId = renderer.Batches[0] - .ReferenceFrames - .First(frame => frame.AttributeName == "onclick") - .AttributeEventHandlerId; - - // Act - var task = renderer.DispatchEventAsync(eventHandlerId, new DerivedEventArgs()); - - // Assert - Assert.NotNull(arg); - Assert.Equal(TaskStatus.Faulted, task.Status); - await Assert.ThrowsAsync(() => task); - } - - [Fact] - public async Task DispatchEventAsync_Delegate_AsynchronousCompletion() - { - // Arrange - var tcs = new TaskCompletionSource(); - - var renderer = new TestRenderer(); - var parentComponent = new OuterEventComponent(); - parentComponent.RenderFragment = (builder) => - { - builder.OpenComponent(0); - builder.AddAttribute(1, nameof(EventComponent.OnClickAsyncAction), (Func)(async () => - { - await tcs.Task; - })); - builder.CloseComponent(); - }; - - var parentComponentId = renderer.AssignRootComponentId(parentComponent); - await parentComponent.TriggerRenderAsync(); - - var eventHandlerId = renderer.Batches[0] - .ReferenceFrames - .First(frame => frame.AttributeName == "onclickaction") - .AttributeEventHandlerId; - - // Act - var task = renderer.DispatchEventAsync(eventHandlerId, new DerivedEventArgs()); - - // Assert - Assert.Equal(TaskStatus.WaitingForActivation, task.Status); - tcs.SetResult(null); - await task; // Does not throw - } - - [Fact] - public async Task DispatchEventAsync_EventCallback_AsynchronousCompletion() - { - // Arrange - var tcs = new TaskCompletionSource(); - - var renderer = new TestRenderer(); - var parentComponent = new OuterEventComponent(); - parentComponent.RenderFragment = (builder) => - { - builder.OpenComponent(0); - builder.AddAttribute(1, nameof(EventComponent.OnClickEventCallback), EventCallback.Factory.Create(parentComponent, async () => - { - await tcs.Task; - })); - builder.CloseComponent(); - }; - - var parentComponentId = renderer.AssignRootComponentId(parentComponent); - await parentComponent.TriggerRenderAsync(); - - var eventHandlerId = renderer.Batches[0] - .ReferenceFrames - .First(frame => frame.AttributeName == "onclick") - .AttributeEventHandlerId; - - // Act - var task = renderer.DispatchEventAsync(eventHandlerId, new DerivedEventArgs()); - - // Assert - Assert.Equal(TaskStatus.WaitingForActivation, task.Status); - tcs.SetResult(null); - await task; // Does not throw - } - - [Fact] - public async Task DispatchEventAsync_EventCallbackOfT_AsynchronousCompletion() - { - // Arrange - var tcs = new TaskCompletionSource(); - - DerivedEventArgs arg = null; - - var renderer = new TestRenderer(); - var parentComponent = new OuterEventComponent(); - parentComponent.RenderFragment = (builder) => - { - builder.OpenComponent(0); - builder.AddAttribute(1, nameof(EventComponent.OnClickEventCallbackOfT), EventCallback.Factory.Create(parentComponent, async (e) => - { - arg = e; - await tcs.Task; - })); - builder.CloseComponent(); - }; - - var parentComponentId = renderer.AssignRootComponentId(parentComponent); - await parentComponent.TriggerRenderAsync(); - - var eventHandlerId = renderer.Batches[0] - .ReferenceFrames - .First(frame => frame.AttributeName == "onclick") - .AttributeEventHandlerId; - - // Act - var task = renderer.DispatchEventAsync(eventHandlerId, new DerivedEventArgs()); - - // Assert - Assert.NotNull(arg); - Assert.Equal(TaskStatus.WaitingForActivation, task.Status); - tcs.SetResult(null); - await task; // Does not throw - } - - [Fact] - public async Task DispatchEventAsync_Delegate_AsynchronousCancellation() - { - // Arrange - var tcs = new TaskCompletionSource(); - - var renderer = new TestRenderer(); - var parentComponent = new OuterEventComponent(); - parentComponent.RenderFragment = (builder) => - { - builder.OpenComponent(0); - builder.AddAttribute(1, nameof(EventComponent.OnClickAsyncAction), (Func)(async () => - { - await tcs.Task; - throw new TaskCanceledException(); - })); - builder.CloseComponent(); - }; - - var parentComponentId = renderer.AssignRootComponentId(parentComponent); - await parentComponent.TriggerRenderAsync(); - - var eventHandlerId = renderer.Batches[0] - .ReferenceFrames - .First(frame => frame.AttributeName == "onclickaction") - .AttributeEventHandlerId; - - // Act - var task = renderer.DispatchEventAsync(eventHandlerId, new DerivedEventArgs()); - - // Assert - Assert.Equal(TaskStatus.WaitingForActivation, task.Status); - tcs.SetResult(null); - - await task; // Does not throw - Assert.Empty(renderer.HandledExceptions); - } - - [Fact] - public async Task DispatchEventAsync_EventCallback_AsynchronousCancellation() - { - // Arrange - var tcs = new TaskCompletionSource(); - - var renderer = new TestRenderer(); - var parentComponent = new OuterEventComponent(); - parentComponent.RenderFragment = (builder) => - { - builder.OpenComponent(0); - builder.AddAttribute(1, nameof(EventComponent.OnClickEventCallback), EventCallback.Factory.Create(parentComponent, async () => - { - await tcs.Task; - throw new TaskCanceledException(); - })); - builder.CloseComponent(); - }; - - var parentComponentId = renderer.AssignRootComponentId(parentComponent); - await parentComponent.TriggerRenderAsync(); - - var eventHandlerId = renderer.Batches[0] - .ReferenceFrames - .First(frame => frame.AttributeName == "onclick") - .AttributeEventHandlerId; - - // Act - var task = renderer.DispatchEventAsync(eventHandlerId, new DerivedEventArgs()); - - // Assert - Assert.Equal(TaskStatus.WaitingForActivation, task.Status); - tcs.SetResult(null); - - await task; // Does not throw - Assert.Empty(renderer.HandledExceptions); - } - - [Fact] - public async Task DispatchEventAsync_EventCallbackOfT_AsynchronousCancellation() - { - // Arrange - var tcs = new TaskCompletionSource(); - - DerivedEventArgs arg = null; - - var renderer = new TestRenderer(); - var parentComponent = new OuterEventComponent(); - parentComponent.RenderFragment = (builder) => - { - builder.OpenComponent(0); - builder.AddAttribute(1, nameof(EventComponent.OnClickEventCallbackOfT), EventCallback.Factory.Create(parentComponent, async (e) => - { - arg = e; - await tcs.Task; - throw new TaskCanceledException(); - })); - builder.CloseComponent(); - }; - - var parentComponentId = renderer.AssignRootComponentId(parentComponent); - await parentComponent.TriggerRenderAsync(); - - var eventHandlerId = renderer.Batches[0] - .ReferenceFrames - .First(frame => frame.AttributeName == "onclick") - .AttributeEventHandlerId; - - // Act - var task = renderer.DispatchEventAsync(eventHandlerId, new DerivedEventArgs()); - - // Assert - Assert.NotNull(arg); - Assert.Equal(TaskStatus.WaitingForActivation, task.Status); - tcs.SetResult(null); - - await task; // Does not throw - Assert.Empty(renderer.HandledExceptions); - } - - [Fact] - public async Task DispatchEventAsync_Delegate_AsynchronousException() - { - // Arrange - var tcs = new TaskCompletionSource(); - - var renderer = new TestRenderer(); - var parentComponent = new OuterEventComponent(); - parentComponent.RenderFragment = (builder) => - { - builder.OpenComponent(0); - builder.AddAttribute(1, nameof(EventComponent.OnClickAsyncAction), (Func)(async () => - { - await tcs.Task; - throw new InvalidTimeZoneException(); - })); - builder.CloseComponent(); - }; - - var parentComponentId = renderer.AssignRootComponentId(parentComponent); - await parentComponent.TriggerRenderAsync(); - - var eventHandlerId = renderer.Batches[0] - .ReferenceFrames - .First(frame => frame.AttributeName == "onclickaction") - .AttributeEventHandlerId; - - // Act - var task = renderer.DispatchEventAsync(eventHandlerId, new DerivedEventArgs()); - - // Assert - Assert.Equal(TaskStatus.WaitingForActivation, task.Status); - tcs.SetResult(null); - - await Assert.ThrowsAsync(() => task); - } - - [Fact] - public async Task DispatchEventAsync_EventCallback_AsynchronousException() - { - // Arrange - var tcs = new TaskCompletionSource(); - - var renderer = new TestRenderer(); - var parentComponent = new OuterEventComponent(); - parentComponent.RenderFragment = (builder) => - { - builder.OpenComponent(0); - builder.AddAttribute(1, nameof(EventComponent.OnClickEventCallback), EventCallback.Factory.Create(parentComponent, async () => - { - await tcs.Task; - throw new InvalidTimeZoneException(); - })); - builder.CloseComponent(); - }; - - var parentComponentId = renderer.AssignRootComponentId(parentComponent); - await parentComponent.TriggerRenderAsync(); - - var eventHandlerId = renderer.Batches[0] - .ReferenceFrames - .First(frame => frame.AttributeName == "onclick") - .AttributeEventHandlerId; - - // Act - var task = renderer.DispatchEventAsync(eventHandlerId, new DerivedEventArgs()); - - // Assert - Assert.Equal(TaskStatus.WaitingForActivation, task.Status); - tcs.SetResult(null); - - await Assert.ThrowsAsync(() => task); - } - - [Fact] - public async Task DispatchEventAsync_EventCallbackOfT_AsynchronousException() - { - // Arrange - var tcs = new TaskCompletionSource(); - - DerivedEventArgs arg = null; - - var renderer = new TestRenderer(); - var parentComponent = new OuterEventComponent(); - parentComponent.RenderFragment = (builder) => - { - builder.OpenComponent(0); - builder.AddAttribute(1, nameof(EventComponent.OnClickEventCallbackOfT), EventCallback.Factory.Create(parentComponent, async (e) => - { - arg = e; - await tcs.Task; - throw new InvalidTimeZoneException(); - })); - builder.CloseComponent(); - }; - - var parentComponentId = renderer.AssignRootComponentId(parentComponent); - await parentComponent.TriggerRenderAsync(); - - var eventHandlerId = renderer.Batches[0] - .ReferenceFrames - .First(frame => frame.AttributeName == "onclick") - .AttributeEventHandlerId; - - // Act - var task = renderer.DispatchEventAsync(eventHandlerId, new DerivedEventArgs()); - - // Assert - Assert.NotNull(arg); - Assert.Equal(TaskStatus.WaitingForActivation, task.Status); - tcs.SetResult(null); - - await Assert.ThrowsAsync(() => task); - } - - [Fact] - public async Task CannotDispatchEventsWithUnknownEventHandlers() - { - // Arrange - var renderer = new TestRenderer(); - - // Act/Assert - await Assert.ThrowsAsync(() => - { - return renderer.DispatchEventAsync(0, new EventArgs()); - }); - } - - [Fact] - public void ComponentsCanBeAssociatedWithMultipleRenderers() - { - // Arrange - var renderer1 = new TestRenderer(); - var renderer2 = new TestRenderer(); - var component = new MultiRendererComponent(); - var renderer1ComponentId = renderer1.AssignRootComponentId(component); - renderer2.AssignRootComponentId(new TestComponent(null)); // Just so they don't get the same IDs - var renderer2ComponentId = renderer2.AssignRootComponentId(component); - - // Act/Assert - component.TriggerRender(); - var renderer1Batch = renderer1.Batches.Single(); - var renderer1Diff = renderer1Batch.DiffsByComponentId[renderer1ComponentId].Single(); - Assert.Collection(renderer1Diff.Edits, - edit => - { - Assert.Equal(RenderTreeEditType.PrependFrame, edit.Type); - AssertFrame.Text(renderer1Batch.ReferenceFrames[edit.ReferenceFrameIndex], - $"Hello from {nameof(MultiRendererComponent)}", 0); - }); - - var renderer2Batch = renderer2.Batches.Single(); - var renderer2Diff = renderer2Batch.DiffsByComponentId[renderer2ComponentId].Single(); - Assert.Collection(renderer2Diff.Edits, - edit => - { - Assert.Equal(RenderTreeEditType.PrependFrame, edit.Type); - AssertFrame.Text(renderer2Batch.ReferenceFrames[edit.ReferenceFrameIndex], - $"Hello from {nameof(MultiRendererComponent)}", 0); - }); - } - - [Fact] - public void PreservesChildComponentInstancesWithNoAttributes() - { - // Arrange: First render, capturing child component instance - var renderer = new TestRenderer(); - var message = "Hello"; - var component = new TestComponent(builder => - { - builder.AddContent(0, message); - builder.OpenComponent(1); - builder.CloseComponent(); - }); - - var rootComponentId = renderer.AssignRootComponentId(component); - component.TriggerRender(); - - var nestedComponentFrame = renderer.Batches.Single() - .ReferenceFrames - .Single(frame => frame.FrameType == RenderTreeFrameType.Component); - var nestedComponentInstance = (MessageComponent)nestedComponentFrame.Component; - - // Act: Second render - message = "Modified message"; - component.TriggerRender(); - - // Assert - var batch = renderer.Batches[1]; - var diff = batch.DiffsByComponentId[rootComponentId].Single(); - Assert.Collection(diff.Edits, - edit => - { - Assert.Equal(RenderTreeEditType.UpdateText, edit.Type); - Assert.Equal(0, edit.ReferenceFrameIndex); - }); - AssertFrame.Text(batch.ReferenceFrames[0], "Modified message"); - Assert.False(batch.DiffsByComponentId.ContainsKey(nestedComponentFrame.ComponentId)); - } - - [Fact] - public void UpdatesPropertiesOnRetainedChildComponentInstances() - { - // Arrange: First render, capturing child component instance - var renderer = new TestRenderer(); - var objectThatWillNotChange = new object(); - var firstRender = true; - var component = new TestComponent(builder => - { - builder.OpenComponent(1); - builder.AddAttribute(2, nameof(FakeComponent.IntProperty), firstRender ? 123 : 256); - builder.AddAttribute(3, nameof(FakeComponent.ObjectProperty), objectThatWillNotChange); - builder.AddAttribute(4, nameof(FakeComponent.StringProperty), firstRender ? "String that will change" : "String that did change"); - builder.CloseComponent(); - }); - - var rootComponentId = renderer.AssignRootComponentId(component); - component.TriggerRender(); - - var originalComponentFrame = renderer.Batches.Single() - .ReferenceFrames - .Single(frame => frame.FrameType == RenderTreeFrameType.Component); - var childComponentInstance = (FakeComponent)originalComponentFrame.Component; - - // Assert 1: properties were assigned - Assert.Equal(123, childComponentInstance.IntProperty); - Assert.Equal("String that will change", childComponentInstance.StringProperty); - Assert.Same(objectThatWillNotChange, childComponentInstance.ObjectProperty); - - // Act: Second render - firstRender = false; - component.TriggerRender(); - - // Assert - Assert.Equal(256, childComponentInstance.IntProperty); - Assert.Equal("String that did change", childComponentInstance.StringProperty); - Assert.Same(objectThatWillNotChange, childComponentInstance.ObjectProperty); - } - - [Fact] - public void ReRendersChildComponentsWhenPropertiesChange() - { - // Arrange: First render - var renderer = new TestRenderer(); - var firstRender = true; - var component = new TestComponent(builder => - { - builder.OpenComponent(1); - builder.AddAttribute(2, nameof(MessageComponent.Message), firstRender ? "first" : "second"); - builder.CloseComponent(); - }); - - var rootComponentId = renderer.AssignRootComponentId(component); - component.TriggerRender(); - - var childComponentId = renderer.Batches.Single() - .ReferenceFrames - .Single(frame => frame.FrameType == RenderTreeFrameType.Component) - .ComponentId; - - // Act: Second render - firstRender = false; - component.TriggerRender(); - var diff = renderer.Batches[1].DiffsByComponentId[childComponentId].Single(); - - // Assert - Assert.Collection(diff.Edits, - edit => - { - Assert.Equal(RenderTreeEditType.UpdateText, edit.Type); - Assert.Equal(0, edit.ReferenceFrameIndex); - }); - AssertFrame.Text(renderer.Batches[1].ReferenceFrames[0], "second"); - } - - [Fact] - public void ReRendersChildComponentWhenUnmatchedValuesChange() - { - // Arrange: First render - var renderer = new TestRenderer(); - var firstRender = true; - var component = new TestComponent(builder => - { - builder.OpenComponent(1); - builder.AddAttribute(1, "class", firstRender ? "first" : "second"); - builder.AddAttribute(2, "id", "some_text"); - builder.AddAttribute(3, nameof(MyStrongComponent.Text), "hi there."); - builder.CloseComponent(); - }); - - var rootComponentId = renderer.AssignRootComponentId(component); - component.TriggerRender(); - - var childComponentId = renderer.Batches.Single() - .ReferenceFrames - .Single(frame => frame.FrameType == RenderTreeFrameType.Component) - .ComponentId; - - // Act: Second render - firstRender = false; - component.TriggerRender(); - var diff = renderer.Batches[1].DiffsByComponentId[childComponentId].Single(); - - // Assert - Assert.Collection(diff.Edits, - edit => - { - Assert.Equal(RenderTreeEditType.SetAttribute, edit.Type); - Assert.Equal(0, edit.ReferenceFrameIndex); - }); - AssertFrame.Attribute(renderer.Batches[1].ReferenceFrames[0], "class", "second"); - } - - // This is a sanity check that diffs of "unmatched" values *just work* without any specialized - // code in the renderer to handle it. All of the data that's used in the diff is contained in - // the render tree, and the diff process does not need to inspect the state of the component. - [Fact] - public void ReRendersDoesNotReRenderChildComponentWhenUnmatchedValuesDoNotChange() - { - // Arrange: First render - var renderer = new TestRenderer(); - var component = new TestComponent(builder => - { - builder.OpenComponent(1); - builder.AddAttribute(1, "class", "cool-beans"); - builder.AddAttribute(2, "id", "some_text"); - builder.AddAttribute(3, nameof(MyStrongComponent.Text), "hi there."); - builder.CloseComponent(); - }); - - var rootComponentId = renderer.AssignRootComponentId(component); - component.TriggerRender(); - - var childComponentId = renderer.Batches.Single() - .ReferenceFrames - .Single(frame => frame.FrameType == RenderTreeFrameType.Component) - .ComponentId; - - // Act: Second render - component.TriggerRender(); - - // Assert - Assert.False(renderer.Batches[1].DiffsByComponentId.ContainsKey(childComponentId)); - } - - [Fact] - public void RenderBatchIncludesListOfDisposedComponents() - { - // Arrange - var renderer = new TestRenderer(); - var firstRender = true; - var component = new TestComponent(builder => - { - if (firstRender) - { - // Nested descendants - builder.OpenComponent>(100); - builder.AddAttribute(101, nameof(ConditionalParentComponent.IncludeChild), true); - builder.CloseComponent(); - } - builder.OpenComponent(200); - builder.CloseComponent(); - }); - - var rootComponentId = renderer.AssignRootComponentId(component); - - // Act/Assert 1: First render, capturing child component IDs - component.TriggerRender(); - var batch = renderer.Batches.Single(); - var rootComponentDiff = batch.DiffsByComponentId[rootComponentId].Single(); - var childComponentIds = rootComponentDiff - .Edits - .Select(edit => batch.ReferenceFrames[edit.ReferenceFrameIndex]) - .Where(frame => frame.FrameType == RenderTreeFrameType.Component) - .Select(frame => frame.ComponentId) - .ToList(); - var childComponent3 = batch.ReferenceFrames.Where(f => f.ComponentId == 3) - .Single().Component; - Assert.Equal(new[] { 1, 2 }, childComponentIds); - Assert.IsType(childComponent3); - - // Act: Second render - firstRender = false; - component.TriggerRender(); - - // Assert: Applicable children are included in disposal list - Assert.Equal(2, renderer.Batches.Count); - Assert.Equal(new[] { 1, 3 }, renderer.Batches[1].DisposedComponentIDs); - - // Act/Assert: If a disposed component requests a render, it's a no-op - var renderHandle = ((FakeComponent)childComponent3).RenderHandle; - renderHandle.Dispatcher.InvokeAsync(() => renderHandle.Render(builder - => throw new NotImplementedException("Should not be invoked"))); - Assert.Equal(2, renderer.Batches.Count); - } - - [Fact] - public void RenderBatch_HandlesExceptionsFromAllDisposedComponents() - { - // Arrange - var renderer = new TestRenderer { ShouldHandleExceptions = true }; - var exception1 = new Exception(); - var exception2 = new Exception(); - - var firstRender = true; - var component = new TestComponent(builder => - { - if (firstRender) - { - builder.AddContent(0, "Hello"); - builder.OpenComponent(1); - builder.AddAttribute(1, nameof(DisposableComponent.DisposeAction), (Action)(() => throw exception1)); - builder.CloseComponent(); - - builder.OpenComponent(2); - builder.AddAttribute(1, nameof(DisposableComponent.DisposeAction), (Action)(() => throw exception2)); - builder.CloseComponent(); - } - }); - var componentId = renderer.AssignRootComponentId(component); - component.TriggerRender(); - - // Act: Second render - firstRender = false; - component.TriggerRender(); - - // Assert: Applicable children are included in disposal list - Assert.Equal(2, renderer.Batches.Count); - Assert.Equal(new[] { 1, 2 }, renderer.Batches[1].DisposedComponentIDs); - - // Outer component is still alive and not disposed. - Assert.False(component.Disposed); - var aex = Assert.IsType(Assert.Single(renderer.HandledExceptions)); - Assert.Contains(exception1, aex.InnerExceptions); - Assert.Contains(exception2, aex.InnerExceptions); - } - - [Fact] - public void RenderBatch_DoesNotDisposeComponentMultipleTimes() - { - // Arrange - var renderer = new TestRenderer { ShouldHandleExceptions = true }; - var exception1 = new Exception(); - var exception2 = new Exception(); - - var count1 = 0; - var count2 = 0; - var count3 = 0; - var count4 = 0; - var count5 = 0; - - var firstRender = true; - var component = new TestComponent(builder => - { - if (firstRender) - { - builder.AddContent(0, "Hello"); - builder.OpenComponent(1); - builder.AddAttribute(1, nameof(DisposableComponent.DisposeAction), (Action)(() => { count1++; })); - builder.CloseComponent(); - - builder.OpenComponent(2); - builder.AddAttribute(1, nameof(DisposableComponent.DisposeAction), (Action)(() => { count2++; throw exception1; })); - builder.CloseComponent(); - - builder.OpenComponent(3); - builder.AddAttribute(1, nameof(DisposableComponent.DisposeAction), (Action)(() => { count3++; })); - builder.CloseComponent(); - } - - builder.OpenComponent(4); - builder.AddAttribute(1, nameof(DisposableComponent.DisposeAction), (Action)(() => { count4++; throw exception2; })); - builder.CloseComponent(); - - builder.OpenComponent(5); - builder.AddAttribute(1, nameof(DisposableComponent.DisposeAction), (Action)(() => { count5++; })); - builder.CloseComponent(); - }); - var componentId = renderer.AssignRootComponentId(component); - component.TriggerRender(); - - // Act: Second render - firstRender = false; - component.TriggerRender(); - - // Assert: Applicable children are included in disposal list - Assert.Equal(2, renderer.Batches.Count); - Assert.Equal(new[] { 1, 2, 3 }, renderer.Batches[1].DisposedComponentIDs); - - // Components "disposed" in the batch were all disposed, components that are still live were not disposed - Assert.Equal(1, count1); - Assert.Equal(1, count2); - Assert.Equal(1, count3); - Assert.Equal(0, count4); - Assert.Equal(0, count5); - - // Outer component is still alive and not disposed. - Assert.False(component.Disposed); - var ex = Assert.IsType(Assert.Single(renderer.HandledExceptions)); - Assert.Same(exception1, ex); - - // Act: Dispose renderer - renderer.Dispose(); - - Assert.Equal(2, renderer.HandledExceptions.Count); - ex = renderer.HandledExceptions[1]; - Assert.Same(exception2, ex); - - // Assert: Everything was disposed once. - Assert.Equal(1, count1); - Assert.Equal(1, count2); - Assert.Equal(1, count3); - Assert.Equal(1, count4); - Assert.Equal(1, count5); - Assert.True(component.Disposed); - } - - [Fact] - public async Task DisposesEventHandlersWhenAttributeValueChanged() - { - // Arrange - var renderer = new TestRenderer(); - var eventCount = 0; - Action origEventHandler = args => { eventCount++; }; - var component = new EventComponent { OnTest = origEventHandler }; - var componentId = renderer.AssignRootComponentId(component); - component.TriggerRender(); - var origEventHandlerId = renderer.Batches.Single() - .ReferenceFrames - .Where(f => f.FrameType == RenderTreeFrameType.Attribute) - .Single(f => f.AttributeEventHandlerId != 0) - .AttributeEventHandlerId; - - // Act/Assert 1: Event handler fires when we trigger it - Assert.Equal(0, eventCount); - var renderTask = renderer.DispatchEventAsync(origEventHandlerId, args: null); - Assert.True(renderTask.IsCompletedSuccessfully); - Assert.Equal(1, eventCount); - await renderTask; - - // Now change the attribute value - var newEventCount = 0; - component.OnTest = args => { newEventCount++; }; - component.TriggerRender(); - - // Act/Assert 2: Can no longer fire the original event, but can fire the new event - await Assert.ThrowsAsync(() => - { - return renderer.DispatchEventAsync(origEventHandlerId, args: null); - }); - - Assert.Equal(1, eventCount); - Assert.Equal(0, newEventCount); - renderTask = renderer.DispatchEventAsync(origEventHandlerId + 1, args: null); - Assert.True(renderTask.IsCompletedSuccessfully); - Assert.Equal(1, newEventCount); - await renderTask; - } - - [Fact] - public async Task DisposesEventHandlersWhenAttributeRemoved() - { - // Arrange - var renderer = new TestRenderer(); - var eventCount = 0; - Action origEventHandler = args => { eventCount++; }; - var component = new EventComponent { OnTest = origEventHandler }; - var componentId = renderer.AssignRootComponentId(component); - component.TriggerRender(); - var origEventHandlerId = renderer.Batches.Single() - .ReferenceFrames - .Where(f => f.FrameType == RenderTreeFrameType.Attribute) - .Single(f => f.AttributeEventHandlerId != 0) - .AttributeEventHandlerId; - - // Act/Assert 1: Event handler fires when we trigger it - Assert.Equal(0, eventCount); - var renderTask = renderer.DispatchEventAsync(origEventHandlerId, args: null); - Assert.True(renderTask.IsCompletedSuccessfully); - Assert.Equal(1, eventCount); - await renderTask; - - // Now remove the event attribute - component.OnTest = null; - component.TriggerRender(); - - // Act/Assert 2: Can no longer fire the original event - await Assert.ThrowsAsync(() => - { - return renderer.DispatchEventAsync(origEventHandlerId, args: null); - }); - Assert.Equal(1, eventCount); - } - - [Fact] - public async Task DisposesEventHandlersWhenOwnerComponentRemoved() - { - // Arrange - var renderer = new TestRenderer(); - var eventCount = 0; - Action origEventHandler = args => { eventCount++; }; - var component = new ConditionalParentComponent - { - IncludeChild = true, - ChildParameters = new Dictionary - { - { nameof(EventComponent.OnTest), origEventHandler } - } - }; - var rootComponentId = renderer.AssignRootComponentId(component); - component.TriggerRender(); - var batch = renderer.Batches.Single(); - var rootComponentDiff = batch.DiffsByComponentId[rootComponentId].Single(); - var rootComponentFrame = batch.ReferenceFrames[0]; - var childComponentFrame = rootComponentDiff.Edits - .Select(e => batch.ReferenceFrames[e.ReferenceFrameIndex]) - .Where(f => f.FrameType == RenderTreeFrameType.Component) - .Single(); - var childComponentId = childComponentFrame.ComponentId; - var childComponentDiff = batch.DiffsByComponentId[childComponentFrame.ComponentId].Single(); - var eventHandlerId = batch.ReferenceFrames - .Skip(childComponentDiff.Edits[0].ReferenceFrameIndex) // Search from where the child component frames start - .Where(f => f.FrameType == RenderTreeFrameType.Attribute) - .Single(f => f.AttributeEventHandlerId != 0) - .AttributeEventHandlerId; - - // Act/Assert 1: Event handler fires when we trigger it - Assert.Equal(0, eventCount); - var renderTask = renderer.DispatchEventAsync(eventHandlerId, args: null); - Assert.True(renderTask.IsCompletedSuccessfully); - Assert.Equal(1, eventCount); - await renderTask; - - // Now remove the EventComponent - component.IncludeChild = false; - component.TriggerRender(); - - // Act/Assert 2: Can no longer fire the original event - await Assert.ThrowsAsync(() => - { - return renderer.DispatchEventAsync(eventHandlerId, args: null); - }); - Assert.Equal(1, eventCount); - } - - [Fact] - public async Task DisposesEventHandlersWhenAncestorElementRemoved() - { - // Arrange - var renderer = new TestRenderer(); - var eventCount = 0; - Action origEventHandler = args => { eventCount++; }; - var component = new EventComponent { OnTest = origEventHandler }; - var componentId = renderer.AssignRootComponentId(component); - component.TriggerRender(); - var origEventHandlerId = renderer.Batches.Single() - .ReferenceFrames - .Where(f => f.FrameType == RenderTreeFrameType.Attribute) - .Single(f => f.AttributeEventHandlerId != 0) - .AttributeEventHandlerId; - - // Act/Assert 1: Event handler fires when we trigger it - Assert.Equal(0, eventCount); - var renderTask = renderer.DispatchEventAsync(origEventHandlerId, args: null); - Assert.True(renderTask.IsCompletedSuccessfully); - Assert.Equal(1, eventCount); - await renderTask; - - // Now remove the ancestor element - component.SkipElement = true; - component.TriggerRender(); - - // Act/Assert 2: Can no longer fire the original event - await Assert.ThrowsAsync(() => - { - return renderer.DispatchEventAsync(origEventHandlerId, args: null); - }); - Assert.Equal(1, eventCount); - } - - [Fact] - public async Task AllRendersTriggeredSynchronouslyDuringEventHandlerAreHandledAsSingleBatch() - { - // Arrange: A root component with a child whose event handler explicitly queues - // a re-render of both the root component and the child - var renderer = new TestRenderer(); - var eventCount = 0; - TestComponent rootComponent = null; - EventComponent childComponent = null; - rootComponent = new TestComponent(builder => - { - builder.AddContent(0, "Child event count: " + eventCount); - builder.OpenComponent(1); - builder.AddAttribute(2, nameof(EventComponent.OnTest), new Action(args => - { - eventCount++; - rootComponent.TriggerRender(); - childComponent.TriggerRender(); - })); - builder.CloseComponent(); - }); - var rootComponentId = renderer.AssignRootComponentId(rootComponent); - rootComponent.TriggerRender(); - var origBatchReferenceFrames = renderer.Batches.Single().ReferenceFrames; - var childComponentFrame = origBatchReferenceFrames - .Single(f => f.Component is EventComponent); - var childComponentId = childComponentFrame.ComponentId; - childComponent = (EventComponent)childComponentFrame.Component; - var origEventHandlerId = origBatchReferenceFrames - .Where(f => f.FrameType == RenderTreeFrameType.Attribute) - .Last(f => f.AttributeEventHandlerId != 0) - .AttributeEventHandlerId; - Assert.Single(renderer.Batches); - - // Act - var renderTask = renderer.DispatchEventAsync(origEventHandlerId, args: null); - - // Assert - Assert.True(renderTask.IsCompletedSuccessfully); - await renderTask; - - Assert.Equal(2, renderer.Batches.Count); - var batch = renderer.Batches.Last(); - Assert.Collection(batch.DiffsInOrder, - diff => - { - // First we triggered the root component to re-render - Assert.Equal(rootComponentId, diff.ComponentId); - Assert.Collection(diff.Edits, edit => - { - Assert.Equal(RenderTreeEditType.UpdateText, edit.Type); - AssertFrame.Text( - batch.ReferenceFrames[edit.ReferenceFrameIndex], - "Child event count: 1"); - }); - }, - diff => - { - // Then the root re-render will have triggered an update to the child - Assert.Equal(childComponentId, diff.ComponentId); - Assert.Collection(diff.Edits, edit => - { - Assert.Equal(RenderTreeEditType.UpdateText, edit.Type); - AssertFrame.Text( - batch.ReferenceFrames[edit.ReferenceFrameIndex], - "Render count: 2"); - }); - }, - diff => - { - // Finally we explicitly requested a re-render of the child - Assert.Equal(childComponentId, diff.ComponentId); - Assert.Collection(diff.Edits, edit => - { - Assert.Equal(RenderTreeEditType.UpdateText, edit.Type); - AssertFrame.Text( - batch.ReferenceFrames[edit.ReferenceFrameIndex], - "Render count: 3"); - }); - }); - } - - [Fact] - public void ComponentCannotTriggerRenderBeforeRenderHandleAssigned() - { - // Arrange - var component = new TestComponent(builder => { }); - - // Act/Assert - var ex = Assert.Throws(() => component.TriggerRender()); - Assert.Equal("The render handle is not yet assigned.", ex.Message); - } - - [Fact] - public void ComponentCanTriggerRenderWhenNoBatchIsInProgress() - { - // Arrange - var renderer = new TestRenderer(); - var renderCount = 0; - var component = new TestComponent(builder => - { - builder.AddContent(0, $"Render count: {++renderCount}"); - }); - var componentId = renderer.AssignRootComponentId(component); - - // Act/Assert: Can trigger initial render - Assert.Equal(0, renderCount); - component.TriggerRender(); - Assert.Equal(1, renderCount); - var batch1 = renderer.Batches.Single(); - var edit1 = batch1.DiffsByComponentId[componentId].Single().Edits.Single(); - Assert.Equal(RenderTreeEditType.PrependFrame, edit1.Type); - AssertFrame.Text(batch1.ReferenceFrames[edit1.ReferenceFrameIndex], - "Render count: 1", 0); - - // Act/Assert: Can trigger subsequent render - component.TriggerRender(); - Assert.Equal(2, renderCount); - var batch2 = renderer.Batches.Skip(1).Single(); - var edit2 = batch2.DiffsByComponentId[componentId].Single().Edits.Single(); - Assert.Equal(RenderTreeEditType.UpdateText, edit2.Type); - AssertFrame.Text(batch2.ReferenceFrames[edit2.ReferenceFrameIndex], - "Render count: 2", 0); - } - - [Fact] - public void ComponentCanTriggerRenderWhenExistingBatchIsInProgress() - { - // Arrange - var renderer = new TestRenderer(); - TestComponent parent = null; - var parentRenderCount = 0; - parent = new TestComponent(builder => - { - builder.OpenComponent(0); - builder.AddAttribute(1, nameof(ReRendersParentComponent.Parent), parent); - builder.CloseComponent(); - builder.AddContent(2, $"Parent render count: {++parentRenderCount}"); - }); - var parentComponentId = renderer.AssignRootComponentId(parent); - - // Act - parent.TriggerRender(); - - // Assert - var batch = renderer.Batches.Single(); - Assert.Equal(4, batch.DiffsInOrder.Count); - - // First is the parent component's initial render - var diff1 = batch.DiffsInOrder[0]; - Assert.Equal(parentComponentId, diff1.ComponentId); - Assert.Collection(diff1.Edits, - edit => - { - Assert.Equal(RenderTreeEditType.PrependFrame, edit.Type); - AssertFrame.Component( - batch.ReferenceFrames[edit.ReferenceFrameIndex]); - }, - edit => - { - Assert.Equal(RenderTreeEditType.PrependFrame, edit.Type); - AssertFrame.Text( - batch.ReferenceFrames[edit.ReferenceFrameIndex], - "Parent render count: 1"); - }); - - // Second is the child component's single render - var diff2 = batch.DiffsInOrder[1]; - Assert.NotEqual(parentComponentId, diff2.ComponentId); - var diff2edit = diff2.Edits.Single(); - Assert.Equal(RenderTreeEditType.PrependFrame, diff2edit.Type); - AssertFrame.Text(batch.ReferenceFrames[diff2edit.ReferenceFrameIndex], - "Child is here"); - - // Third is the parent's triggered render - var diff3 = batch.DiffsInOrder[2]; - Assert.Equal(parentComponentId, diff3.ComponentId); - var diff3edit = diff3.Edits.Single(); - Assert.Equal(RenderTreeEditType.UpdateText, diff3edit.Type); - AssertFrame.Text(batch.ReferenceFrames[diff3edit.ReferenceFrameIndex], - "Parent render count: 2"); - - // Fourth is child's rerender due to parent rendering - var diff4 = batch.DiffsInOrder[3]; - Assert.NotEqual(parentComponentId, diff4.ComponentId); - Assert.Empty(diff4.Edits); - } - - [Fact] - public void QueuedRenderIsSkippedIfComponentWasAlreadyDisposedInSameBatch() - { - // Arrange - var renderer = new TestRenderer(); - var shouldRenderChild = true; - TestComponent component = null; - component = new TestComponent(builder => - { - builder.AddContent(0, "Some frame so the child isn't at position zero"); - if (shouldRenderChild) - { - builder.OpenComponent(1); - builder.AddAttribute(2, "onclick", (Action)((object obj) => - { - // First we queue (1) a re-render of the root component, then the child component - // will queue (2) its own re-render. But by the time (1) completes, the child will - // have been disposed, even though (2) is still in the queue - shouldRenderChild = false; - component.TriggerRender(); - })); - builder.CloseComponent(); - } - }); - - var componentId = renderer.AssignRootComponentId(component); - component.TriggerRender(); - var childComponentId = renderer.Batches.Single() - .ReferenceFrames - .Where(f => f.ComponentId != 0) - .Single() - .ComponentId; - var origEventHandlerId = renderer.Batches.Single() - .ReferenceFrames - .Where(f => f.FrameType == RenderTreeFrameType.Attribute && f.AttributeName == "onmycustomevent") - .Single(f => f.AttributeEventHandlerId != 0) - .AttributeEventHandlerId; - - // Act - // The fact that there's no error here is the main thing we're testing - var renderTask = renderer.DispatchEventAsync(origEventHandlerId, args: null); - - // Assert: correct render result - Assert.True(renderTask.IsCompletedSuccessfully); - var newBatch = renderer.Batches.Skip(1).Single(); - Assert.Equal(1, newBatch.DisposedComponentIDs.Count); - Assert.Equal(1, newBatch.DiffsByComponentId.Count); - Assert.Collection(newBatch.DiffsByComponentId[componentId].Single().Edits, - edit => - { - Assert.Equal(RenderTreeEditType.RemoveFrame, edit.Type); - Assert.Equal(1, edit.SiblingIndex); - }); - } - - [Fact] - public async Task CanCombineBindAndConditionalAttribute() - { - // This test represents https://github.com/aspnet/Blazor/issues/624 - - // Arrange: Rendered with textbox enabled - var renderer = new TestRenderer(); - var component = new BindPlusConditionalAttributeComponent(); - var componentId = renderer.AssignRootComponentId(component); - component.TriggerRender(); - var checkboxChangeEventHandlerId = renderer.Batches.Single() - .ReferenceFrames - .First(frame => frame.FrameType == RenderTreeFrameType.Attribute && frame.AttributeEventHandlerId != 0) - .AttributeEventHandlerId; - - // Act: Toggle the checkbox - var eventArgs = new ChangeEventArgs { Value = true }; - var renderTask = renderer.DispatchEventAsync(checkboxChangeEventHandlerId, eventArgs); - - Assert.True(renderTask.IsCompletedSuccessfully); - var latestBatch = renderer.Batches.Last(); - var latestDiff = latestBatch.DiffsInOrder.Single(); - var referenceFrames = latestBatch.ReferenceFrames; - - // Assert: Textbox's "disabled" attribute was removed - Assert.Equal(2, renderer.Batches.Count); - Assert.Equal(componentId, latestDiff.ComponentId); - Assert.Contains(latestDiff.Edits, edit => - edit.SiblingIndex == 1 - && edit.RemovedAttributeName == "disabled"); - - await renderTask; - } - - [Fact] - public void HandlesNestedElementCapturesDuringRefresh() - { - // This may seem like a very arbitrary test case, but at once stage there was a bug - // whereby the diff output was incorrect given a ref capture on an element whose - // parent element also had a ref capture - - // Arrange - var attrValue = 0; - var component = new TestComponent(builder => - { - builder.OpenElement(0, "parent elem"); - builder.AddAttribute(1, "parent elem attr", attrValue); - builder.AddElementReferenceCapture(2, _ => { }); - builder.OpenElement(3, "child elem"); - builder.AddElementReferenceCapture(4, _ => { }); - builder.AddContent(5, "child text"); - builder.CloseElement(); - builder.CloseElement(); - }); - var renderer = new TestRenderer(); - renderer.AssignRootComponentId(component); - - // Act: Update the attribute value on the parent - component.TriggerRender(); - attrValue++; - component.TriggerRender(); - - // Assert - var latestBatch = renderer.Batches.Skip(1).Single(); - var latestDiff = latestBatch.DiffsInOrder.Single(); - Assert.Collection(latestDiff.Edits, - edit => - { - Assert.Equal(RenderTreeEditType.SetAttribute, edit.Type); - Assert.Equal(0, edit.SiblingIndex); - AssertFrame.Attribute(latestBatch.ReferenceFrames[edit.ReferenceFrameIndex], - "parent elem attr", 1); - }); - } - - [Fact] - public void CallsAfterRenderOnEachRender() - { - // Arrange - var onAfterRenderCallCountLog = new List(); - var component = new AfterRenderCaptureComponent(); - var renderer = new TestRenderer - { - OnUpdateDisplay = _ => onAfterRenderCallCountLog.Add(component.OnAfterRenderCallCount) - }; - renderer.AssignRootComponentId(component); - - // Act - component.TriggerRender(); - - // Assert - // When the display was first updated, OnAfterRender had not yet been called - Assert.Equal(new[] { 0 }, onAfterRenderCallCountLog); - // But OnAfterRender was called since then - Assert.Equal(1, component.OnAfterRenderCallCount); - - // Act/Assert 2: On a subsequent render, the same happens again - component.TriggerRender(); - Assert.Equal(new[] { 0, 1 }, onAfterRenderCallCountLog); - Assert.Equal(2, component.OnAfterRenderCallCount); - } - - [Fact] - public void CallsAfterRenderAfterTheUIHasFinishedUpdatingAsynchronously() - { - // Arrange - var @event = new ManualResetEventSlim(); - var tcs = new TaskCompletionSource(); - var afterRenderTcs = new TaskCompletionSource(); - var onAfterRenderCallCountLog = new List(); - var component = new AsyncAfterRenderComponent(afterRenderTcs.Task) - { - OnAfterRenderComplete = () => @event.Set(), - }; - var renderer = new AsyncUpdateTestRenderer() - { - OnUpdateDisplayAsync = _ => tcs.Task, - }; - renderer.AssignRootComponentId(component); - - // Act - component.TriggerRender(); - tcs.SetResult(null); - afterRenderTcs.SetResult(null); - - // We need to wait here because the completions from SetResult will be scheduled. - @event.Wait(Timeout); - - // Assert - Assert.True(component.Called); - } - - [Fact] - public void CallsAfterRenderAfterTheUIHasFinishedUpdatingSynchronously() - { - // Arrange - var @event = new ManualResetEventSlim(); - var afterRenderTcs = new TaskCompletionSource(); - var onAfterRenderCallCountLog = new List(); - var component = new AsyncAfterRenderComponent(afterRenderTcs.Task) - { - OnAfterRenderComplete = () => @event.Set(), - }; - var renderer = new AsyncUpdateTestRenderer() - { - OnUpdateDisplayAsync = _ => Task.CompletedTask - }; - renderer.AssignRootComponentId(component); - - // Act - component.TriggerRender(); - afterRenderTcs.SetResult(null); - - // We need to wait here because the completions from SetResult will be scheduled. - @event.Wait(Timeout); - - // Assert - Assert.True(component.Called); - } - - [Fact] - public void DoesNotCallOnAfterRenderForComponentsNotRendered() - { - // Arrange - var showComponent3 = true; - var parentComponent = new TestComponent(builder => - { - // First child will be re-rendered because we'll change its param - builder.OpenComponent(0); - builder.AddAttribute(1, "some param", showComponent3); - builder.CloseComponent(); - - // Second child will not be re-rendered because nothing changes - builder.OpenComponent(2); - builder.CloseComponent(); - - // Third component will be disposed - if (showComponent3) - { - builder.OpenComponent(3); - builder.CloseComponent(); - } - }); - var renderer = new TestRenderer(); - var parentComponentId = renderer.AssignRootComponentId(parentComponent); - - // Act: First render - parentComponent.TriggerRender(); - - // Assert: All child components were notified of "after render" - var batch1 = renderer.Batches.Single(); - var parentComponentEdits1 = batch1.DiffsByComponentId[parentComponentId].Single().Edits; - var childComponents = parentComponentEdits1 - .Select( - edit => (AfterRenderCaptureComponent)batch1.ReferenceFrames[edit.ReferenceFrameIndex].Component) - .ToArray(); - Assert.Equal(1, childComponents[0].OnAfterRenderCallCount); - Assert.Equal(1, childComponents[1].OnAfterRenderCallCount); - Assert.Equal(1, childComponents[2].OnAfterRenderCallCount); - - // Act: Second render - showComponent3 = false; - parentComponent.TriggerRender(); - - // Assert: Only the re-rendered component was notified of "after render" - var batch2 = renderer.Batches.Skip(1).Single(); - Assert.Equal(2, batch2.DiffsInOrder.Count); // Parent and first child - Assert.Equal(1, batch2.DisposedComponentIDs.Count); // Third child - Assert.Equal(2, childComponents[0].OnAfterRenderCallCount); // Retained and re-rendered - Assert.Equal(1, childComponents[1].OnAfterRenderCallCount); // Retained and not re-rendered - Assert.Equal(1, childComponents[2].OnAfterRenderCallCount); // Disposed - } - - [Fact] - public void CanTriggerRenderingSynchronouslyFromInsideAfterRenderCallback() - { - // Arrange - AfterRenderCaptureComponent component = null; - component = new AfterRenderCaptureComponent - { - OnAfterRenderLogic = () => - { - if (component.OnAfterRenderCallCount < 10) - { - component.TriggerRender(); - } - } - }; - var renderer = new TestRenderer(); - renderer.AssignRootComponentId(component); - - // Act - component.TriggerRender(); - - // Assert - Assert.Equal(10, component.OnAfterRenderCallCount); - } - - [ConditionalFact] - [SkipOnHelix("https://github.com/aspnet/AspNetCore/issues/7487")] - public async Task CanTriggerEventHandlerDisposedInEarlierPendingBatchAsync() - { - // This represents the scenario where the same event handler is being triggered - // rapidly, such as an input event while typing. It only applies to asynchronous - // batch updates, i.e., server-side Components. - // Sequence: - // 1. The client dispatches event X twice (say) in quick succession - // 2. The server receives the first instance, handles the event, and re-renders - // some component. The act of re-rendering causes the old event handler to be - // replaced by a new one, so the old one is flagged to be disposed. - // 3. The server receives the second instance. Even though the corresponding event - // handler is flagged to be disposed, we have to still be able to find and - // execute it without errors. - - // Arrange - var renderer = new TestAsyncRenderer - { - NextUpdateDisplayReturnTask = Task.CompletedTask - }; - var numEventsFired = 0; - EventComponent component = null; - Action eventHandler = null; - - eventHandler = _ => - { - numEventsFired++; - - // Replace the old event handler with a different one, - // (old the old handler ID will be disposed) then re-render. - component.OnTest = args => eventHandler(args); - component.TriggerRender(); - }; - - component = new EventComponent { OnTest = eventHandler }; - var componentId = renderer.AssignRootComponentId(component); - component.TriggerRender(); - - var eventHandlerId = renderer.Batches.Single() - .ReferenceFrames - .First(frame => frame.AttributeValue != null) - .AttributeEventHandlerId; - - // Act/Assert 1: Event can be fired for the first time - var render1TCS = new TaskCompletionSource(); - renderer.NextUpdateDisplayReturnTask = render1TCS.Task; - await renderer.DispatchEventAsync(eventHandlerId, new EventArgs()); - Assert.Equal(1, numEventsFired); - - // Act/Assert 2: *Same* event handler ID can be reused prior to completion of - // preceding UI update - var render2TCS = new TaskCompletionSource(); - renderer.NextUpdateDisplayReturnTask = render2TCS.Task; - await renderer.DispatchEventAsync(eventHandlerId, new EventArgs()); - Assert.Equal(2, numEventsFired); - - // Act/Assert 3: After we complete the first UI update in which a given - // event handler ID is disposed, we can no longer reuse that event handler ID - - // From here we can't see when the async disposal is completed. Just give it plenty of time (Task.Yield isn't enough). - // There is a small chance in which the continuations from TaskCompletionSource run asynchronously. - // In that case we might not be able to see the results from RemoveEventHandlerIds as they might run asynchronously. - // For that case, we are going to queue a continuation on render1TCS.Task, include a 1s delay and await the resulting - // task to offer the best chance that we get to see the error in all cases. - var awaitableTask = render1TCS.Task.ContinueWith(_ => Task.Delay(1000)).Unwrap(); - render1TCS.SetResult(null); - await awaitableTask; - var ex = await Assert.ThrowsAsync(() => - { - return renderer.DispatchEventAsync(eventHandlerId, new EventArgs()); - }); - Assert.Contains($"There is no event handler associated with this event. EventId: '{eventHandlerId}'.", ex.Message); - Assert.Equal(2, numEventsFired); - } - - [Fact] - public void ExceptionsThrownSynchronouslyCanBeHandledSynchronously() - { - // Arrange - var renderer = new TestRenderer { ShouldHandleExceptions = true }; - var component = new NestedAsyncComponent(); - var exception = new InvalidTimeZoneException(); - - // Act/Assert - var componentId = renderer.AssignRootComponentId(component); - var task = renderer.RenderRootComponentAsync(componentId, ParameterView.FromDictionary(new Dictionary - { - [nameof(NestedAsyncComponent.EventActions)] = new Dictionary> - { - [0] = new[] - { - new NestedAsyncComponent.ExecutionAction - { - Event = NestedAsyncComponent.EventType.OnInitAsyncAsync, - EventAction = () => throw exception, - }, - } - }, - [nameof(NestedAsyncComponent.WhatToRender)] = new Dictionary> - { - [0] = CreateRenderFactory(Array.Empty()), - }, - })); - - Assert.True(task.IsCompletedSuccessfully); - Assert.Equal(new[] { exception }, renderer.HandledExceptions); - } - - [Fact] - public void ExceptionsThrownSynchronouslyCanBeHandled() - { - // Arrange - var renderer = new TestRenderer { ShouldHandleExceptions = true }; - var component = new NestedAsyncComponent(); - var exception = new InvalidTimeZoneException(); - - // Act/Assert - var componentId = renderer.AssignRootComponentId(component); - var renderTask = renderer.RenderRootComponentAsync(componentId, ParameterView.FromDictionary(new Dictionary - { - [nameof(NestedAsyncComponent.EventActions)] = new Dictionary> - { - [0] = new[] - { - new NestedAsyncComponent.ExecutionAction - { - Event = NestedAsyncComponent.EventType.OnInitAsyncAsync, - EventAction = () => throw exception, - }, - } - }, - [nameof(NestedAsyncComponent.WhatToRender)] = new Dictionary> - { - [0] = CreateRenderFactory(Array.Empty()), - }, - })); - - Assert.True(renderTask.IsCompletedSuccessfully); - Assert.Equal(new[] { exception }, renderer.HandledExceptions); - } - - [Fact] - public void ExceptionsReturnedUsingTaskFromExceptionCanBeHandled() - { - // Arrange - var renderer = new TestRenderer { ShouldHandleExceptions = true }; - var component = new NestedAsyncComponent(); - var exception = new InvalidTimeZoneException(); - - // Act/Assert - var componentId = renderer.AssignRootComponentId(component); - var renderTask = renderer.RenderRootComponentAsync(componentId, ParameterView.FromDictionary(new Dictionary - { - [nameof(NestedAsyncComponent.EventActions)] = new Dictionary> - { - [0] = new[] - { - new NestedAsyncComponent.ExecutionAction - { - Event = NestedAsyncComponent.EventType.OnInitAsyncAsync, - EventAction = () => Task.FromException<(int, NestedAsyncComponent.EventType)>(exception), - }, - } - }, - [nameof(NestedAsyncComponent.WhatToRender)] = new Dictionary> - { - [0] = CreateRenderFactory(Array.Empty()), - }, - })); - - Assert.True(renderTask.IsCompletedSuccessfully); - Assert.Equal(new[] { exception }, renderer.HandledExceptions); - } - - [Fact] - public async Task ExceptionsThrownAsynchronouslyDuringFirstRenderCanBeHandled() - { - // Arrange - var renderer = new TestRenderer { ShouldHandleExceptions = true }; - var component = new NestedAsyncComponent(); - var tcs = new TaskCompletionSource(); - var exception = new InvalidTimeZoneException(); - - // Act/Assert - var componentId = renderer.AssignRootComponentId(component); - var renderTask = renderer.RenderRootComponentAsync(componentId, ParameterView.FromDictionary(new Dictionary - { - [nameof(NestedAsyncComponent.EventActions)] = new Dictionary> - { - [0] = new[] - { - new NestedAsyncComponent.ExecutionAction - { - Event = NestedAsyncComponent.EventType.OnInitAsyncAsync, - EventAction = async () => - { - await tcs.Task; - throw exception; - } - }, - } - }, - [nameof(NestedAsyncComponent.WhatToRender)] = new Dictionary> - { - [0] = CreateRenderFactory(Array.Empty()), - }, - })); - - Assert.False(renderTask.IsCompleted); - tcs.SetResult(0); - await renderTask; - Assert.Same(exception, Assert.Single(renderer.HandledExceptions).GetBaseException()); - } - - [Fact] - public async Task ExceptionsThrownAsynchronouslyAfterFirstRenderCanBeHandled() - { - // This differs from the "during first render" case, because some aspects of the rendering - // code paths are special cased for the first render because of prerendering. - - // Arrange - var @event = new ManualResetEventSlim(); - var renderer = new TestRenderer() - { - ShouldHandleExceptions = true, - OnExceptionHandled = () => { @event.Set(); }, - }; - var taskToAwait = Task.CompletedTask; - var component = new TestComponent(builder => - { - builder.OpenComponent(0); - builder.AddAttribute(1, nameof(ComponentThatAwaitsTask.TaskToAwait), taskToAwait); - builder.CloseComponent(); - }); - var componentId = renderer.AssignRootComponentId(component); - await renderer.RenderRootComponentAsync(componentId); // Not throwing on first render - - var asyncExceptionTcs = new TaskCompletionSource(); - taskToAwait = asyncExceptionTcs.Task; - await renderer.Dispatcher.InvokeAsync(component.TriggerRender); - - // Act - var exception = new InvalidOperationException(); - - @event.Reset(); - asyncExceptionTcs.SetException(exception); - - // We need to wait here because the continuations of SetException will be scheduled to run asynchronously. - @event.Wait(Timeout); - - // Assert - Assert.Same(exception, Assert.Single(renderer.HandledExceptions).GetBaseException()); - } - - [Fact] - public async Task ExceptionsThrownAsynchronouslyFromMultipleComponentsCanBeHandled() - { - // Arrange - var renderer = new TestRenderer { ShouldHandleExceptions = true }; - var component = new NestedAsyncComponent(); - var exception1 = new InvalidTimeZoneException(); - var exception2 = new UriFormatException(); - var tcs = new TaskCompletionSource(); - - // Act/Assert - var componentId = renderer.AssignRootComponentId(component); - var renderTask = renderer.RenderRootComponentAsync(componentId, ParameterView.FromDictionary(new Dictionary - { - [nameof(NestedAsyncComponent.EventActions)] = new Dictionary> - { - [0] = Array.Empty(), - [1] = new List - { - new NestedAsyncComponent.ExecutionAction - { - Event = NestedAsyncComponent.EventType.OnInitAsyncAsync, - EventAction = async () => - { - await tcs.Task; - throw exception1; - } - }, - }, - [2] = new List - { - new NestedAsyncComponent.ExecutionAction - { - Event = NestedAsyncComponent.EventType.OnInitAsyncAsync, - EventAction = async () => - { - await tcs.Task; - throw exception2; - } - }, - }, - }, - [nameof(NestedAsyncComponent.WhatToRender)] = new Dictionary> - { - [0] = CreateRenderFactory(new[] { 1, 2, }), - [1] = CreateRenderFactory(Array.Empty()), - [2] = CreateRenderFactory(Array.Empty()), - }, - })); - - Assert.False(renderTask.IsCompleted); - tcs.SetResult(0); - - await renderTask; - Assert.Equal(2, renderer.HandledExceptions.Count); - Assert.Contains(exception1, renderer.HandledExceptions); - Assert.Contains(exception2, renderer.HandledExceptions); - } - - [Fact] - public void ExceptionsThrownSynchronouslyFromMultipleComponentsCanBeHandled() - { - // Arrange - var renderer = new TestRenderer { ShouldHandleExceptions = true }; - var component = new NestedAsyncComponent(); - var exception1 = new InvalidTimeZoneException(); - var exception2 = new UriFormatException(); - - // Act/Assert - var componentId = renderer.AssignRootComponentId(component); - var renderTask = renderer.RenderRootComponentAsync(componentId, ParameterView.FromDictionary(new Dictionary - { - [nameof(NestedAsyncComponent.EventActions)] = new Dictionary> - { - [0] = Array.Empty(), - [1] = new List - { - new NestedAsyncComponent.ExecutionAction - { - Event = NestedAsyncComponent.EventType.OnInitAsyncAsync, - EventAction = () => - { - throw exception1; - } - }, - }, - [2] = new List - { - new NestedAsyncComponent.ExecutionAction - { - Event = NestedAsyncComponent.EventType.OnInitAsyncAsync, - EventAction = () => - { - throw exception2; - } - }, - }, - }, - [nameof(NestedAsyncComponent.WhatToRender)] = new Dictionary> - { - [0] = CreateRenderFactory(new[] { 1, 2, }), - [1] = CreateRenderFactory(Array.Empty()), - [2] = CreateRenderFactory(Array.Empty()), - }, - })); - - Assert.True(renderTask.IsCompletedSuccessfully); - - Assert.Equal(2, renderer.HandledExceptions.Count); - Assert.Contains(exception1, renderer.HandledExceptions); - Assert.Contains(exception2, renderer.HandledExceptions); - } - - [Fact] - public async Task ExceptionsThrownFromHandleAfterRender_Sync_AreHandled() - { - // Arrange - var renderer = new TestRenderer { ShouldHandleExceptions = true }; - var component = new NestedAsyncComponent(); - var exception = new InvalidTimeZoneException(); - - var taskCompletionSource = new TaskCompletionSource(); - - // Act/Assert - var componentId = renderer.AssignRootComponentId(component); - var renderTask = renderer.RenderRootComponentAsync(componentId, ParameterView.FromDictionary(new Dictionary - { - [nameof(NestedAsyncComponent.EventActions)] = new Dictionary> - { - [0] = new[] - { - new NestedAsyncComponent.ExecutionAction - { - Event = NestedAsyncComponent.EventType.OnAfterRenderAsyncSync, - EventAction = () => - { - throw exception; - }, - } - }, - [1] = new[] - { - new NestedAsyncComponent.ExecutionAction - { - Event = NestedAsyncComponent.EventType.OnAfterRenderAsyncSync, - EventAction = () => - { - taskCompletionSource.TrySetResult(0); - return Task.FromResult((1, NestedAsyncComponent.EventType.OnAfterRenderAsyncSync)); - }, - } - } - }, - [nameof(NestedAsyncComponent.WhatToRender)] = new Dictionary> - { - [0] = CreateRenderFactory(new[] { 1 }), - [1] = CreateRenderFactory(Array.Empty()), - }, - })); - - Assert.True(renderTask.IsCompletedSuccessfully); - - // OnAfterRenderAsync happens in the background. Make it more predictable, by gating it until we're ready to capture exceptions. - await taskCompletionSource.Task.TimeoutAfter(TimeSpan.FromSeconds(10)); - Assert.Same(exception, Assert.Single(renderer.HandledExceptions).GetBaseException()); - } - - [Fact] - public async Task ExceptionsThrownFromHandleAfterRender_Async_AreHandled() - { - // Arrange - var renderer = new TestRenderer { ShouldHandleExceptions = true }; - var component = new NestedAsyncComponent(); - var exception = new InvalidTimeZoneException(); - - var taskCompletionSource = new TaskCompletionSource(); - - // Act/Assert - var componentId = renderer.AssignRootComponentId(component); - var renderTask = renderer.RenderRootComponentAsync(componentId, ParameterView.FromDictionary(new Dictionary - { - [nameof(NestedAsyncComponent.EventActions)] = new Dictionary> - { - [0] = new[] - { - new NestedAsyncComponent.ExecutionAction - { - Event = NestedAsyncComponent.EventType.OnAfterRenderAsyncAsync, - EventAction = async () => - { - await Task.Yield(); - throw exception; - }, - } - }, - [1] = new[] - { - new NestedAsyncComponent.ExecutionAction - { - Event = NestedAsyncComponent.EventType.OnAfterRenderAsyncAsync, - EventAction = async () => - { - await Task.Yield(); - taskCompletionSource.TrySetResult(0); - return (1, NestedAsyncComponent.EventType.OnAfterRenderAsyncAsync); - }, - } - } - }, - [nameof(NestedAsyncComponent.WhatToRender)] = new Dictionary> - { - [0] = CreateRenderFactory(new[] { 1 }), - [1] = CreateRenderFactory(Array.Empty()), - }, - })); - - Assert.True(renderTask.IsCompletedSuccessfully); - - // OnAfterRenderAsync happens in the background. Make it more predictable, by gating it until we're ready to capture exceptions. - await taskCompletionSource.Task.TimeoutAfter(TimeSpan.FromSeconds(10)); - Assert.Same(exception, Assert.Single(renderer.HandledExceptions).GetBaseException()); - } - - [Fact] - public async Task ExceptionThrownFromConstructor() - { - // Arrange - var renderer = new TestRenderer { ShouldHandleExceptions = true }; - var component = new TestComponent(builder => - { - builder.OpenComponent(0); - builder.CloseComponent(); - }); - - // Act/Assert - var componentId = renderer.AssignRootComponentId(component); - var renderTask = renderer.RenderRootComponentAsync(componentId); - - await renderTask; - Assert.True(renderTask.IsCompletedSuccessfully); - Assert.Same(ConstructorThrowingComponent.Exception, Assert.Single(renderer.HandledExceptions).GetBaseException()); - } - - private class ConstructorThrowingComponent : IComponent - { - public static readonly Exception Exception = new InvalidTimeZoneException(); - - public ConstructorThrowingComponent() - { - throw Exception; - } - - public void Attach(RenderHandle renderHandle) - { - throw new NotImplementedException(); - } - - public Task SetParametersAsync(ParameterView parameters) - { - throw new NotImplementedException(); - } - } - - [Fact] - public async Task ExceptionThrownFromAttach() - { - // Arrange - var renderer = new TestRenderer { ShouldHandleExceptions = true }; - var component = new TestComponent(builder => - { - builder.OpenComponent(0); - builder.CloseComponent(); - }); - - // Act/Assert - var componentId = renderer.AssignRootComponentId(component); - var renderTask = renderer.RenderRootComponentAsync(componentId); - - await renderTask; - Assert.True(renderTask.IsCompletedSuccessfully); - Assert.Same(AttachThrowingComponent.Exception, Assert.Single(renderer.HandledExceptions).GetBaseException()); - } - - private class AttachThrowingComponent : IComponent - { - public static readonly Exception Exception = new InvalidTimeZoneException(); - - public void Attach(RenderHandle renderHandle) - { - throw Exception; - } - - public Task SetParametersAsync(ParameterView parameters) - { - throw new NotImplementedException(); - } - } - - [Fact] - public void SynchronousCancelledTasks_HandleAfterRender_Works() - { - // Arrange - var renderer = new TestRenderer { ShouldHandleExceptions = true }; - var component = new NestedAsyncComponent(); - var tcs = new TaskCompletionSource<(int, NestedAsyncComponent.EventType)>(); - tcs.TrySetCanceled(); - - // Act/Assert - var componentId = renderer.AssignRootComponentId(component); - var renderTask = renderer.RenderRootComponentAsync(componentId, ParameterView.FromDictionary(new Dictionary - { - [nameof(NestedAsyncComponent.EventActions)] = new Dictionary> - { - [0] = new[] - { - new NestedAsyncComponent.ExecutionAction - { - Event = NestedAsyncComponent.EventType.OnAfterRenderAsyncAsync, - EventAction = () => tcs.Task, - } - }, - }, - [nameof(NestedAsyncComponent.WhatToRender)] = new Dictionary> - { - [0] = CreateRenderFactory(Array.Empty()), - }, - })); - - // Rendering should finish synchronously - Assert.True(renderTask.IsCompletedSuccessfully); - Assert.Empty(renderer.HandledExceptions); - } - - [Fact] - public void AsynchronousCancelledTasks_HandleAfterRender_Works() - { - // Arrange - var renderer = new TestRenderer { ShouldHandleExceptions = true }; - var component = new NestedAsyncComponent(); - var tcs = new TaskCompletionSource<(int, NestedAsyncComponent.EventType)>(); - - // Act/Assert - var componentId = renderer.AssignRootComponentId(component); - var renderTask = renderer.RenderRootComponentAsync(componentId, ParameterView.FromDictionary(new Dictionary - { - [nameof(NestedAsyncComponent.EventActions)] = new Dictionary> - { - [0] = new[] - { - new NestedAsyncComponent.ExecutionAction - { - Event = NestedAsyncComponent.EventType.OnAfterRenderAsyncAsync, - EventAction = () => tcs.Task, - } - }, - }, - [nameof(NestedAsyncComponent.WhatToRender)] = new Dictionary> - { - [0] = CreateRenderFactory(Array.Empty()), - }, - })); - - // Rendering should be complete. - Assert.True(renderTask.IsCompletedSuccessfully); - tcs.TrySetCanceled(); - Assert.Empty(renderer.HandledExceptions); - } - - [Fact] - public async Task CanceledTasksInHandleAfterRender_AreIgnored() - { - // Arrange - var renderer = new TestRenderer { ShouldHandleExceptions = true }; - var component = new NestedAsyncComponent(); - var taskCompletionSource = new TaskCompletionSource(); - var cancellationTokenSource = new CancellationTokenSource(); - cancellationTokenSource.Cancel(); - - // Act/Assert - var componentId = renderer.AssignRootComponentId(component); - await renderer.RenderRootComponentAsync(componentId, ParameterView.FromDictionary(new Dictionary - { - [nameof(NestedAsyncComponent.EventActions)] = new Dictionary> - { - [0] = new[] - { - new NestedAsyncComponent.ExecutionAction - { - Event = NestedAsyncComponent.EventType.OnAfterRenderAsyncSync, - EventAction = () => - { - taskCompletionSource.TrySetResult(0); - cancellationTokenSource.Token.ThrowIfCancellationRequested(); - return default; - }, - } - }, - }, - [nameof(NestedAsyncComponent.WhatToRender)] = new Dictionary> - { - [0] = CreateRenderFactory(Array.Empty()), - }, - })); - - await taskCompletionSource.Task.TimeoutAfter(TimeSpan.FromSeconds(10)); - - Assert.Empty(renderer.HandledExceptions); - } - - [Fact] - public void DisposingRenderer_DisposesTopLevelComponents() - { - // Arrange - var renderer = new TestRenderer(); - var component = new DisposableComponent(); - renderer.AssignRootComponentId(component); - - // Act - renderer.Dispose(); - - // Assert - Assert.True(component.Disposed); - } - - [Fact] - public void DisposingRenderer_RejectsAttemptsToStartMoreRenderBatches() - { - // Arrange - var renderer = new TestRenderer(); - renderer.Dispose(); - - // Act/Assert - var ex = Assert.Throws(() => renderer.ProcessPendingRender()); - Assert.Contains("Cannot process pending renders after the renderer has been disposed.", ex.Message); - } - - [Fact] - public void WhenRendererIsDisposed_ComponentRenderRequestsAreSkipped() - { - // The important point of this is that user code in components may continue to call - // StateHasChanged (e.g., after an async task completion), and we don't want that to - // show up as an error. In general, components should skip rendering after disposal. - // This test shows that we don't add any new entries to the render queue after disposal. - // There's a different test showing that if the render queue entry was already added - // before a component got individually disposed, that render queue entry gets skipped. - - // Arrange - var renderer = new TestRenderer(); - var component = new DisposableComponent(); - renderer.AssignRootComponentId(component); - - // Act - renderer.Dispose(); - component.TriggerRender(); - - // Assert: no exception, no batch produced - Assert.Empty(renderer.Batches); - } - - [Fact] - public void DisposingRenderer_DisposesNestedComponents() - { - // Arrange - var renderer = new TestRenderer(); - var component = new TestComponent(builder => - { - builder.AddContent(0, "Hello"); - builder.OpenComponent(1); - builder.CloseComponent(); - }); - var componentId = renderer.AssignRootComponentId(component); - component.TriggerRender(); - var batch = renderer.Batches.Single(); - var componentFrame = batch.ReferenceFrames - .Single(frame => frame.FrameType == RenderTreeFrameType.Component); - var nestedComponent = Assert.IsType(componentFrame.Component); - - // Act - renderer.Dispose(); - - // Assert - Assert.True(component.Disposed); - Assert.True(nestedComponent.Disposed); - } - - [Fact] - public void DisposingRenderer_CapturesExceptionsFromAllRegisteredComponents() - { - // Arrange - var renderer = new TestRenderer { ShouldHandleExceptions = true }; - var exception1 = new Exception(); - var exception2 = new Exception(); - var component = new TestComponent(builder => - { - builder.AddContent(0, "Hello"); - builder.OpenComponent(1); - builder.AddAttribute(1, nameof(DisposableComponent.DisposeAction), (Action)(() => throw exception1)); - builder.CloseComponent(); - - builder.OpenComponent(2); - builder.AddAttribute(1, nameof(DisposableComponent.DisposeAction), (Action)(() => throw exception2)); - builder.CloseComponent(); - }); - var componentId = renderer.AssignRootComponentId(component); - component.TriggerRender(); - - // Act &A Assert - renderer.Dispose(); - - // All components must be disposed even if some throw as part of being diposed. - Assert.True(component.Disposed); - var aex = Assert.IsType(Assert.Single(renderer.HandledExceptions)); - Assert.Contains(exception1, aex.InnerExceptions); - Assert.Contains(exception2, aex.InnerExceptions); - } - - [Theory] - [InlineData(null)] // No existing attribute to update - [InlineData("old property value")] // Has existing attribute to update - public void EventFieldInfoCanPatchTreeSoDiffDoesNotUpdateAttribute(string oldValue) - { - // Arrange: Render a component with an event handler - var renderer = new TestRenderer(); - var component = new BoundPropertyComponent { BoundString = oldValue }; - var componentId = renderer.AssignRootComponentId(component); - component.TriggerRender(); - - var eventHandlerId = renderer.Batches.Single() - .ReferenceFrames - .First(frame => frame.FrameType == RenderTreeFrameType.Attribute && frame.AttributeEventHandlerId > 0) - .AttributeEventHandlerId; - - // Act: Fire event and re-render - var eventFieldInfo = new EventFieldInfo - { - FieldValue = "new property value", - ComponentId = componentId - }; - var dispatchEventTask = renderer.DispatchEventAsync(eventHandlerId, eventFieldInfo, new ChangeEventArgs - { - Value = "new property value" - }); - Assert.True(dispatchEventTask.IsCompletedSuccessfully); - - // Assert: Property was updated, but the diff doesn't include changing the - // element attribute, since we told it the element attribute was already updated - Assert.Equal("new property value", component.BoundString); - Assert.Equal(2, renderer.Batches.Count); - var batch2 = renderer.Batches[1]; - Assert.Collection(batch2.DiffsInOrder.Single().Edits.ToArray(), edit => - { - // The only edit is updating the event handler ID, since the test component - // deliberately uses a capturing lambda. The whole point of this test is to - // show that the diff does *not* update the BoundString value attribute. - Assert.Equal(RenderTreeEditType.SetAttribute, edit.Type); - var attributeFrame = batch2.ReferenceFrames[edit.ReferenceFrameIndex]; - AssertFrame.Attribute(attributeFrame, "ontestevent", typeof(Action)); - Assert.NotEqual(default, attributeFrame.AttributeEventHandlerId); - Assert.NotEqual(eventHandlerId, attributeFrame.AttributeEventHandlerId); - }); - } - - [Fact] - public void EventFieldInfoWorksWhenEventHandlerIdWasSuperseded() - { - // Arrange: Render a component with an event handler - // We want the renderer to think none of the "UpdateDisplay" calls ever complete, because we - // want to keep reusing the same eventHandlerId and not let it get disposed - var renderCompletedTcs = new TaskCompletionSource(); - var renderer = new TestRenderer { NextRenderResultTask = renderCompletedTcs.Task }; - var component = new BoundPropertyComponent { BoundString = "old property value" }; - var componentId = renderer.AssignRootComponentId(component); - - component.TriggerRender(); - - var eventHandlerId = renderer.Batches.Single() - .ReferenceFrames - .First(frame => frame.FrameType == RenderTreeFrameType.Attribute && frame.AttributeEventHandlerId > 0) - .AttributeEventHandlerId; - - // Act: Fire event and re-render *repeatedly*, without changing to use a newer event handler ID, - // even though we know the event handler ID is getting updated in successive diffs - for (var i = 0; i < 10; i++) - { - var newPropertyValue = $"new property value {i}"; - var fieldInfo = new EventFieldInfo - { - ComponentId = componentId, - FieldValue = newPropertyValue, - }; - var dispatchEventTask = renderer.DispatchEventAsync(eventHandlerId, fieldInfo, new ChangeEventArgs - { - Value = newPropertyValue - }); - Assert.True(dispatchEventTask.IsCompletedSuccessfully); - - // Assert: Property was updated, but the diff doesn't include changing the - // element attribute, since we told it the element attribute was already updated - Assert.Equal(newPropertyValue, component.BoundString); - Assert.Equal(i + 2, renderer.Batches.Count); - var latestBatch = renderer.Batches.Last(); - Assert.Collection(latestBatch.DiffsInOrder.Single().Edits.ToArray(), edit => - { - // The only edit is updating the event handler ID, since the test component - // deliberately uses a capturing lambda. The whole point of this test is to - // show that the diff does *not* update the BoundString value attribute. - Assert.Equal(RenderTreeEditType.SetAttribute, edit.Type); - var attributeFrame = latestBatch.ReferenceFrames[edit.ReferenceFrameIndex]; - AssertFrame.Attribute(attributeFrame, "ontestevent", typeof(Action)); - Assert.NotEqual(default, attributeFrame.AttributeEventHandlerId); - Assert.NotEqual(eventHandlerId, attributeFrame.AttributeEventHandlerId); - }); - } - } - - [Fact] - public void CannotStartOverlappingBatches() - { - // Arrange - var renderer = new InvalidRecursiveRenderer(); - var component = new CallbackOnRenderComponent(() => - { - // The renderer disallows one batch to be started inside another, because that - // would violate all kinds of state tracking invariants. It's not something that - // would ever happen except if you subclass the renderer and do something unsupported - // that commences batches from inside each other. - renderer.ProcessPendingRender(); - }); - var componentId = renderer.AssignRootComponentId(component); - - // Act/Assert - var ex = Assert.Throws( - () => renderer.RenderRootComponent(componentId)); - Assert.Contains("Cannot start a batch when one is already in progress.", ex.Message); - } - - [Fact] - public void CannotAccessParameterViewAfterSynchronousReturn() - { - // Arrange - var renderer = new TestRenderer(); - var rootComponent = new TestComponent(builder => - { - builder.OpenComponent(0); - builder.AddAttribute(1, nameof(ParameterViewIllegalCapturingComponent.SomeParam), 0); - builder.CloseComponent(); - }); - var rootComponentId = renderer.AssignRootComponentId(rootComponent); - - // Note that we're not waiting for the async render to complete, since we want to assert - // about the situation immediately after the component yields the thread - renderer.RenderRootComponentAsync(rootComponentId); - - // Act/Assert - var capturingComponent = (ParameterViewIllegalCapturingComponent)renderer.GetCurrentRenderTreeFrames(rootComponentId).Array[0].Component; - var parameterView = capturingComponent.CapturedParameterView; - - // All public APIs on capturingComponent should be electrified now - // Internal APIs don't have to be, because we won't call them at the wrong time - Assert.Throws(() => parameterView.GetEnumerator()); - Assert.Throws(() => parameterView.GetValueOrDefault("anything")); - Assert.Throws(() => parameterView.SetParameterProperties(new object())); - Assert.Throws(() => parameterView.ToDictionary()); - var ex = Assert.Throws(() => parameterView.TryGetValue("anything", out _)); - - // It's enough to assert about one of the messages - Assert.Equal($"The {nameof(ParameterView)} instance can no longer be read because it has expired. {nameof(ParameterView)} can only be read synchronously and must not be stored for later use.", ex.Message); - } - - private class NoOpRenderer : Renderer - { - public NoOpRenderer() : base(new TestServiceProvider(), NullLoggerFactory.Instance) - { - } - - public override Dispatcher Dispatcher { get; } = Dispatcher.CreateDefault(); - - public new int AssignRootComponentId(IComponent component) - => base.AssignRootComponentId(component); - - protected override void HandleException(Exception exception) - => throw new NotImplementedException(); - - protected override Task UpdateDisplayAsync(in RenderBatch renderBatch) - => Task.CompletedTask; - } - - private class TestComponent : IComponent, IDisposable - { - private RenderHandle _renderHandle; - private RenderFragment _renderFragment; - - public TestComponent(RenderFragment renderFragment) - { - _renderFragment = renderFragment; - } - - public void Attach(RenderHandle renderHandle) - { - _renderHandle = renderHandle; - } - - public Task SetParametersAsync(ParameterView parameters) - { - TriggerRender(); - return Task.CompletedTask; - } - - public void TriggerRender() - { - var t = _renderHandle.Dispatcher.InvokeAsync(() => _renderHandle.Render(_renderFragment)); - // This should always be run synchronously - Assert.True(t.IsCompleted); - if (t.IsFaulted) - { - var exception = t.Exception.Flatten().InnerException; - while (exception is AggregateException e) - { - exception = e.InnerException; - } - ExceptionDispatchInfo.Capture(exception).Throw(); - } - } - - public bool Disposed { get; private set; } - - void IDisposable.Dispose() => Disposed = true; - } - - private class MessageComponent : AutoRenderComponent - { - [Parameter] - public string Message { get; set; } - - protected override void BuildRenderTree(RenderTreeBuilder builder) - { - builder.AddContent(0, Message); - } - } - - private class MyStrongComponent : AutoRenderComponent - { - [Parameter(CaptureUnmatchedValues = true)] public IDictionary Attributes { get; set; } - - [Parameter] public string Text { get; set; } - - protected override void BuildRenderTree(RenderTreeBuilder builder) - { - builder.OpenElement(0, "strong"); - builder.AddMultipleAttributes(1, Attributes); - builder.AddContent(2, Text); - builder.CloseElement(); - } - } - - private class FakeComponent : IComponent - { - [Parameter] - public int IntProperty { get; set; } - - [Parameter] - public string StringProperty { get; set; } - - [Parameter] - public object ObjectProperty { get; set; } - - public RenderHandle RenderHandle { get; private set; } - - public void Attach(RenderHandle renderHandle) - => RenderHandle = renderHandle; - - public Task SetParametersAsync(ParameterView parameters) - { - parameters.SetParameterProperties(this); - return Task.CompletedTask; - } - } - - private class EventComponent : AutoRenderComponent, IComponent, IHandleEvent - { - [Parameter] - public Action OnTest { get; set; } - - [Parameter] - public Func OnTestAsync { get; set; } - - [Parameter] - public Action OnClick { get; set; } - - [Parameter] - public Func OnClickAsync { get; set; } - - [Parameter] - public Action OnClickAction { get; set; } - - [Parameter] - public Func OnClickAsyncAction { get; set; } - - [Parameter] - public EventCallback OnClickEventCallback { get; set; } - - [Parameter] - public EventCallback OnClickEventCallbackOfT { get; set; } - - public bool SkipElement { get; set; } - private int renderCount = 0; - - protected override void BuildRenderTree(RenderTreeBuilder builder) - { - builder.OpenElement(0, "grandparent"); - if (!SkipElement) - { - builder.OpenElement(1, "parent"); - builder.OpenElement(2, "some element"); - - if (OnTest != null) - { - builder.AddAttribute(3, "ontest", OnTest); - } - else if (OnTestAsync != null) - { - builder.AddAttribute(3, "ontest", OnTestAsync); - } - - if (OnClick != null) - { - builder.AddAttribute(4, "onclick", OnClick); - } - else if (OnClickAsync != null) - { - builder.AddAttribute(4, "onclick", OnClickAsync); - } - else if (OnClickEventCallback.HasDelegate) - { - builder.AddAttribute(4, "onclick", OnClickEventCallback); - } - else if (OnClickEventCallbackOfT.HasDelegate) - { - builder.AddAttribute(4, "onclick", OnClickEventCallbackOfT); - } - - if (OnClickAction != null) - { - builder.AddAttribute(5, "onclickaction", OnClickAction); - } - else if (OnClickAsyncAction != null) - { - builder.AddAttribute(5, "onclickaction", OnClickAsyncAction); - } - builder.CloseElement(); - builder.CloseElement(); - } - builder.CloseElement(); - builder.AddContent(6, $"Render count: {++renderCount}"); - } - - public Task HandleEventAsync(EventCallbackWorkItem callback, object arg) - { - // Notice, we don't re-render. - return callback.InvokeAsync(arg); - } - } - - private class ConditionalParentComponent : AutoRenderComponent where T : IComponent - { - [Parameter] - public bool IncludeChild { get; set; } - - [Parameter] - public IDictionary ChildParameters { get; set; } - - protected override void BuildRenderTree(RenderTreeBuilder builder) - { - builder.AddContent(0, "Parent here"); - - if (IncludeChild) - { - builder.OpenComponent(1); - if (ChildParameters != null) - { - var sequence = 2; - foreach (var kvp in ChildParameters) - { - builder.AddAttribute(sequence++, kvp.Key, kvp.Value); - } - } - builder.CloseComponent(); - } - } - } - - private class ReRendersParentComponent : AutoRenderComponent - { - [Parameter] - public TestComponent Parent { get; set; } - - private bool _isFirstTime = true; - - protected override void BuildRenderTree(RenderTreeBuilder builder) - { - if (_isFirstTime) // Don't want an infinite loop - { - _isFirstTime = false; - Parent.TriggerRender(); - } - - builder.AddContent(0, "Child is here"); - } - } - - private class RendersSelfAfterEventComponent : IComponent, IHandleEvent - { - [Parameter] - public Action OnClick { get; set; } - - private RenderHandle _renderHandle; - - public void Attach(RenderHandle renderHandle) - => _renderHandle = renderHandle; - - public Task SetParametersAsync(ParameterView parameters) - { - parameters.SetParameterProperties(this); - Render(); - return Task.CompletedTask; - } - - public Task HandleEventAsync(EventCallbackWorkItem callback, object arg) - { - var task = callback.InvokeAsync(arg); - Render(); - return task; - } - - private void Render() - => _renderHandle.Render(builder => - { - builder.OpenElement(0, "my button"); - builder.AddAttribute(1, "onmycustomevent", EventCallback.Factory.Create(this, eventArgs => OnClick(eventArgs))); - builder.CloseElement(); - }); - } - - private class MultiRendererComponent : IComponent - { - private readonly List _renderHandles - = new List(); - - public void Attach(RenderHandle renderHandle) - => _renderHandles.Add(renderHandle); - - public Task SetParametersAsync(ParameterView parameters) - { - return Task.CompletedTask; - } - - public void TriggerRender() - { - foreach (var renderHandle in _renderHandles) - { - renderHandle.Dispatcher.InvokeAsync(() => renderHandle.Render(builder => - { - builder.AddContent(0, $"Hello from {nameof(MultiRendererComponent)}"); - })); - } - } - } - - private class BindPlusConditionalAttributeComponent : AutoRenderComponent, IHandleEvent - { - public bool CheckboxEnabled; - public string SomeStringProperty; - - public Task HandleEventAsync(EventCallbackWorkItem callback, object arg) - { - var task = callback.InvokeAsync(arg); - TriggerRender(); - return task; - } - - protected override void BuildRenderTree(RenderTreeBuilder builder) - { - builder.OpenElement(0, "input"); - builder.AddAttribute(1, "type", "checkbox"); - builder.AddAttribute(2, "value", BindConverter.FormatValue(CheckboxEnabled)); - builder.AddAttribute(3, "onchange", EventCallback.Factory.CreateBinder(this, __value => CheckboxEnabled = __value, CheckboxEnabled)); - builder.CloseElement(); - builder.OpenElement(4, "input"); - builder.AddAttribute(5, "value", BindConverter.FormatValue(SomeStringProperty)); - builder.AddAttribute(6, "onchange", EventCallback.Factory.CreateBinder(this, __value => SomeStringProperty = __value, SomeStringProperty)); - builder.AddAttribute(7, "disabled", !CheckboxEnabled); - builder.CloseElement(); - } - } - - private class AfterRenderCaptureComponent : AutoRenderComponent, IComponent, IHandleAfterRender - { - public Action OnAfterRenderLogic { get; set; } - - public int OnAfterRenderCallCount { get; private set; } - - public Task OnAfterRenderAsync() - { - OnAfterRenderCallCount++; - OnAfterRenderLogic?.Invoke(); - return Task.CompletedTask; - } - - Task IComponent.SetParametersAsync(ParameterView parameters) - { - TriggerRender(); - return Task.CompletedTask; - } - - protected override void BuildRenderTree(RenderTreeBuilder builder) - { - } - } - - private class DisposableComponent : AutoRenderComponent, IDisposable - { - public bool Disposed { get; private set; } - - [Parameter] - public Action DisposeAction { get; set; } - - public void Dispose() - { - Disposed = true; - DisposeAction?.Invoke(); - } - - protected override void BuildRenderTree(RenderTreeBuilder builder) - { - } - } - - class TestAsyncRenderer : TestRenderer - { - public Task NextUpdateDisplayReturnTask { get; set; } - - protected override Task UpdateDisplayAsync(in RenderBatch renderBatch) - { - base.UpdateDisplayAsync(renderBatch); - return NextUpdateDisplayReturnTask; - } - } - - private class AsyncComponent : IComponent - { - private RenderHandle _renderHandler; - - public AsyncComponent(Task taskToAwait, int number) - { - _taskToAwait = taskToAwait; - Number = number; - } - - private readonly Task _taskToAwait; - - public int Number { get; set; } - - public void Attach(RenderHandle renderHandle) - { - _renderHandler = renderHandle; - } - - public async Task SetParametersAsync(ParameterView parameters) - { - int n; - while (Number > 0) - { - n = Number; - _renderHandler.Render(CreateFragment); - Number--; - await _taskToAwait; - }; - - // Cheap closure - void CreateFragment(RenderTreeBuilder builder) - { - var s = 0; - builder.OpenElement(s++, "p"); - builder.AddContent(s++, n); - builder.CloseElement(); - } - } - } - - private class OuterEventComponent : IComponent, IHandleEvent - { - private RenderHandle _renderHandle; - - public RenderFragment RenderFragment { get; set; } - - public Action OnEvent { get; set; } - - public int SomeMethodCallCount { get; set; } - - public void SomeMethod() - { - SomeMethodCallCount++; - } - - public void Attach(RenderHandle renderHandle) - { - _renderHandle = renderHandle; - } - - public Task HandleEventAsync(EventCallbackWorkItem callback, object arg) - { - var task = callback.InvokeAsync(arg); - OnEvent?.Invoke(); - return task; - } - - public Task SetParametersAsync(ParameterView parameters) - { - return TriggerRenderAsync(); - } - - public Task TriggerRenderAsync() => _renderHandle.Dispatcher.InvokeAsync(() => _renderHandle.Render(RenderFragment)); - } - - private void AssertStream(int expectedId, (int id, NestedAsyncComponent.EventType @event)[] logStream) - { - // OnInit runs first - Assert.Equal((expectedId, NestedAsyncComponent.EventType.OnInit), logStream[0]); - - // OnInit async completes - Assert.Single(logStream.Skip(1), - e => e == (expectedId, NestedAsyncComponent.EventType.OnInitAsyncAsync) || e == (expectedId, NestedAsyncComponent.EventType.OnInitAsyncSync)); - - var parametersSetEvent = logStream.Where(le => le == (expectedId, NestedAsyncComponent.EventType.OnParametersSet)).ToArray(); - // OnParametersSet gets called at least once - Assert.NotEmpty(parametersSetEvent); - - var parametersSetAsyncEvent = logStream - .Where(le => le == (expectedId, NestedAsyncComponent.EventType.OnParametersSetAsyncAsync) || - le == (expectedId, NestedAsyncComponent.EventType.OnParametersSetAsyncSync)) - .ToArray(); - // OnParametersSetAsync async gets called at least once - Assert.NotEmpty(parametersSetAsyncEvent); - - // The same number of OnParametersSet and OnParametersSetAsync get produced - Assert.Equal(parametersSetEvent.Length, parametersSetAsyncEvent.Length); - - // The log ends with an OnParametersSetAsync event - Assert.True(logStream.Last() == (expectedId, NestedAsyncComponent.EventType.OnParametersSetAsyncSync) || - logStream.Last() == (expectedId, NestedAsyncComponent.EventType.OnParametersSetAsyncAsync)); - } - - private Func CreateRenderFactory(int[] childrenToRender) - { - // For some reason nameof doesn't work inside a nested lambda, so capturing the value here. - var eventActionsName = nameof(NestedAsyncComponent.EventActions); - var whatToRenderName = nameof(NestedAsyncComponent.WhatToRender); - var testIdName = nameof(NestedAsyncComponent.TestId); - var logName = nameof(NestedAsyncComponent.Log); - - return component => builder => - { - var s = 0; - builder.OpenElement(s++, "div"); - builder.AddContent(s++, $"Id: {component.TestId} BuildRenderTree, {Guid.NewGuid()}"); - foreach (var child in childrenToRender) - { - builder.OpenComponent(s++); - builder.AddAttribute(s++, eventActionsName, component.EventActions); - builder.AddAttribute(s++, whatToRenderName, component.WhatToRender); - builder.AddAttribute(s++, testIdName, child); - builder.AddAttribute(s++, logName, component.Log); - builder.CloseComponent(); - } - - builder.CloseElement(); - }; - } - - private class NestedAsyncComponent : ComponentBase - { - [Parameter] public IDictionary> EventActions { get; set; } - - [Parameter] public IDictionary> WhatToRender { get; set; } - - [Parameter] public int TestId { get; set; } - - [Parameter] public ConcurrentQueue<(int testId, EventType @event)> Log { get; set; } - - protected override void OnInitialized() - { - if (TryGetEntry(EventType.OnInit, out var entry)) - { - var result = entry.EventAction(); - Assert.True(result.IsCompleted, "Task must complete synchronously."); - LogResult(result.Result); - } - } - - protected override async Task OnInitializedAsync() - { - if (TryGetEntry(EventType.OnInitAsyncSync, out var entrySync)) - { - var result = entrySync.EventAction(); - Assert.True(result.IsCompleted, "Task must complete synchronously."); - LogResult(result.Result); - } - else if (TryGetEntry(EventType.OnInitAsyncAsync, out var entryAsync)) - { - var result = await entryAsync.EventAction(); - LogResult(result); - } - } - - protected override void OnParametersSet() - { - if (TryGetEntry(EventType.OnParametersSet, out var entry)) - { - var result = entry.EventAction(); - Assert.True(result.IsCompleted, "Task must complete synchronously."); - LogResult(result.Result); - } - base.OnParametersSet(); - } - - protected override async Task OnParametersSetAsync() - { - if (TryGetEntry(EventType.OnParametersSetAsyncSync, out var entrySync)) - { - var result = entrySync.EventAction(); - Assert.True(result.IsCompleted, "Task must complete synchronously."); - LogResult(result.Result); - } - else if (TryGetEntry(EventType.OnParametersSetAsyncAsync, out var entryAsync)) - { - var result = await entryAsync.EventAction(); - LogResult(result); - } - } - - protected override void BuildRenderTree(RenderTreeBuilder builder) - { - var renderFactory = WhatToRender[TestId]; - renderFactory(this)(builder); - } - - protected override async Task OnAfterRenderAsync(bool firstRender) - { - if (TryGetEntry(EventType.OnAfterRenderAsyncSync, out var entrySync)) - { - var result = entrySync.EventAction(); - Assert.True(result.IsCompleted, "Task must complete synchronously."); - LogResult(result.Result); - } - if (TryGetEntry(EventType.OnAfterRenderAsyncAsync, out var entryAsync)) - { - var result = await entryAsync.EventAction(); - LogResult(result); - } - } - - private bool TryGetEntry(EventType eventType, out ExecutionAction entry) - { - var entries = EventActions[TestId]; - if (entries == null) - { - throw new InvalidOperationException("Failed to find entries for component with Id: " + TestId); - } - entry = entries.FirstOrDefault(e => e.Event == eventType); - return entry != null; - } - - private void LogResult((int, EventType) entry) - { - Log?.Enqueue(entry); - } - - public class ExecutionAction - { - public EventType Event { get; set; } - public Func> EventAction { get; set; } - - public static ExecutionAction On(int id, EventType @event, bool async = false) - { - if (!async) - { - return new ExecutionAction - { - Event = @event, - EventAction = () => Task.FromResult((id, @event)) - }; - } - else - { - return new ExecutionAction - { - Event = @event, - EventAction = async () => - { - await Task.Yield(); - return (id, @event); - } - }; - } - } - } - - public enum EventType - { - OnInit, - OnInitAsyncSync, - OnInitAsyncAsync, - OnParametersSet, - OnParametersSetAsyncSync, - OnParametersSetAsyncAsync, - OnAfterRenderAsyncSync, - OnAfterRenderAsyncAsync, - } - } - - private class ComponentThatAwaitsTask : ComponentBase - { - [Parameter] public Task TaskToAwait { get; set; } - - protected override async Task OnParametersSetAsync() - { - await TaskToAwait; - } - } - - private class AsyncUpdateTestRenderer : TestRenderer - { - public Func OnUpdateDisplayAsync { get; set; } - - protected override Task UpdateDisplayAsync(in RenderBatch renderBatch) - { - return OnUpdateDisplayAsync(renderBatch); - } - } - - private class AsyncAfterRenderComponent : AutoRenderComponent, IHandleAfterRender - { - private readonly Task _task; - - public AsyncAfterRenderComponent(Task task) - { - _task = task; - } - - public bool Called { get; private set; } - - public Action OnAfterRenderComplete { get; set; } - - public async Task OnAfterRenderAsync() - { - await _task; - Called = true; - - OnAfterRenderComplete?.Invoke(); - } - - protected override void BuildRenderTree(RenderTreeBuilder builder) - { - builder.OpenElement(0, "p"); - builder.CloseElement(); - } - } - - class BoundPropertyComponent : AutoRenderComponent - { - public string BoundString { get; set; } - - protected override void BuildRenderTree(RenderTreeBuilder builder) - { - var unrelatedThingToMakeTheLambdaCapture = new object(); - - builder.OpenElement(0, "element with event"); - builder.AddAttribute(1, nameof(BoundString), BoundString); - builder.AddAttribute(2, "ontestevent", new Action((ChangeEventArgs eventArgs) => - { - BoundString = (string)eventArgs.Value; - TriggerRender(); - GC.KeepAlive(unrelatedThingToMakeTheLambdaCapture); - })); - builder.SetUpdatesAttributeName(nameof(BoundString)); - builder.CloseElement(); - } - } - - private class DerivedEventArgs : EventArgs - { - } - - class CallbackOnRenderComponent : AutoRenderComponent - { - private readonly Action _callback; - - public CallbackOnRenderComponent(Action callback) - { - _callback = callback; - } - - protected override void BuildRenderTree(RenderTreeBuilder builder) - => _callback(); - } - - class InvalidRecursiveRenderer : TestRenderer - { - public new void ProcessPendingRender() - => base.ProcessPendingRender(); - } - - class ParameterViewIllegalCapturingComponent : IComponent - { - public ParameterView CapturedParameterView { get; private set; } - - [Parameter] public int SomeParam { get; set; } - - public void Attach(RenderHandle renderHandle) - { - } - - public Task SetParametersAsync(ParameterView parameters) - { - CapturedParameterView = parameters; - - // Return a task that never completes to show that access is forbidden - // after the synchronous return, not just after the returned task completes - return new TaskCompletionSource().Task; - } - } - } -} diff --git a/src/Components/Components/test/Rendering/ArrayBuilderSegmentTest.cs b/src/Components/Components/test/Rendering/ArrayBuilderSegmentTest.cs deleted file mode 100644 index 3e6a22fb6f..0000000000 --- a/src/Components/Components/test/Rendering/ArrayBuilderSegmentTest.cs +++ /dev/null @@ -1,55 +0,0 @@ -// 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 Microsoft.AspNetCore.Components.RenderTree; -using Xunit; - -namespace Microsoft.AspNetCore.Components.Rendering -{ - public class ArrayBuilderSegmentTest - { - [Fact] - public void BasicPropertiesWork() - { - // Arrange: builder containing 1..5 - using var builder = new ArrayBuilder(); - builder.Append(new[] { 1, 2, 3, 4, 5 }, 0, 5); - - // Act: take segment containing 2..3 - var segment = builder.ToSegment(1, 3); - - // Act - Assert.Same(builder.Buffer, segment.Array); - Assert.Equal(1, segment.Offset); - Assert.Equal(2, segment.Count); - Assert.Equal(2, segment[0]); - Assert.Equal(3, segment[1]); - Assert.Equal(new[] { 2, 3 }, segment); - } - - [Fact] - public void StillWorksAfterUnderlyingCapacityChange() - { - // Arrange: builder containing 1..8 - using var builder = new ArrayBuilder(minCapacity: 10, new TestArrayPool()); - builder.Append(new[] { 1, 2, 3, 4, 5, 6, 7, 8 }, 0, 8); - var originalBuffer = builder.Buffer; - - // Act/Assert 1: take segment containing 1..5 - var segment = builder.ToSegment(0, 5); - Assert.Equal(new[] { 1, 2, 3, 4, 5 }, segment); - Assert.Same(originalBuffer, segment.Array); - - // Act 2: grow the builder enough to force a resize - builder.Append(new[] { 9, 10, 11 }, 0, 3); - Array.Clear(originalBuffer, 0, originalBuffer.Length); // Extra proof that we're not using the original storage - - // Assert 2 - Assert.Same(builder.Buffer, segment.Array); - Assert.NotSame(originalBuffer, segment.Array); // Since there was a resize - Assert.Equal(new[] { 1, 2, 3, 4, 5 }, segment); - Assert.Equal(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }, builder.ToSegment(0, builder.Count)); - } - } -} diff --git a/src/Components/Components/test/Rendering/ArrayBuilderTest.cs b/src/Components/Components/test/Rendering/ArrayBuilderTest.cs deleted file mode 100644 index d1aae06064..0000000000 --- a/src/Components/Components/test/Rendering/ArrayBuilderTest.cs +++ /dev/null @@ -1,334 +0,0 @@ -// 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.Buffers; -using System.Linq; -using Xunit; - -namespace Microsoft.AspNetCore.Components.RenderTree -{ - public class ArrayBuilderTest - { - private readonly TestArrayPool ArrayPool = new TestArrayPool(); - - [Fact] - public void Append_SingleItem() - { - // Arrange - var value = 7; - using var builder = CreateArrayBuilder(); - - // Act - builder.Append(value); - - // Assert - Assert.Equal(1, builder.Count); - Assert.Equal(value, builder.Buffer[0]); - } - - [Fact] - public void Append_ThreeItem() - { - // Arrange - var value1 = 7; - var value2 = 22; - var value3 = 3; - using var builder = CreateArrayBuilder(); - - // Act - builder.Append(value1); - builder.Append(value2); - builder.Append(value3); - - // Assert - Assert.Equal(3, builder.Count); - Assert.Equal(new[] { value1, value2, value3 }, builder.Buffer.Take(3)); - } - - [Fact] - public void Append_FillBuffer() - { - // Arrange - var capacity = 8; - using var builder = new ArrayBuilder(minCapacity: capacity); - - // Act - for (var i = 0; i < capacity; i++) - { - builder.Append(5); - } - - // Assert - Assert.Equal(capacity, builder.Count); - Assert.Equal(Enumerable.Repeat(5, capacity), builder.Buffer.Take(capacity)); - } - - [Fact] - public void AppendArray_CopySubset() - { - // Arrange - var array = Enumerable.Repeat(8, 5).ToArray(); - using var builder = CreateArrayBuilder(); - - // Act - builder.Append(array, 0, 2); - - // Assert - Assert.Equal(2, builder.Count); - Assert.Equal(new[] { 8, 8 }, builder.Buffer.Take(2)); - } - - [Fact] - public void AppendArray_CopyArray() - { - // Arrange - var array = Enumerable.Repeat(8, 5).ToArray(); - using var builder = CreateArrayBuilder(); - - // Act - builder.Append(array, 0, array.Length); - - // Assert - Assert.Equal(array.Length, builder.Count); - Assert.Equal(array, builder.Buffer.Take(array.Length)); - } - - [Fact] - public void AppendArray_AfterPriorInsertion() - { - // Arrange - var array = Enumerable.Repeat(8, 5).ToArray(); - using var builder = CreateArrayBuilder(); - - // Act - builder.Append(118); - builder.Append(array, 0, 2); - - // Assert - Assert.Equal(3, builder.Count); - Assert.Equal(new[] { 118, 8, 8 }, builder.Buffer.Take(3)); - } - - [Theory] - // These are at boundaries of our capacity increments. - [InlineData(1023)] - [InlineData(1024)] - [InlineData(1025)] - public void AppendArray_LargerThanBuffer(int size) - { - // Arrange - var array = Enumerable.Repeat(17, size).ToArray(); - using var builder = CreateArrayBuilder(); - - // Act - builder.Append(array, 0, array.Length); - - // Assert - Assert.Equal(array.Length, builder.Count); - Assert.Equal(array, builder.Buffer.Take(array.Length)); - } - - [Fact] - public void Overwrite_Works() - { - // Arrange - using var builder = CreateArrayBuilder(); - builder.Append(7); - builder.Append(3); - builder.Append(9); - - // Act - builder.Overwrite(1, 2); - - // Assert - Assert.Equal(3, builder.Count); - Assert.Equal(new[]{ 7, 2, 9}, builder.Buffer.Take(3)); - } - - [Fact] - public void Insert_Works() - { - // Arrange - using var builder = CreateArrayBuilder(); - builder.Append(7); - builder.Append(3); - builder.Append(9); - - // Act - builder.InsertExpensive(1, 2); - - // Assert - Assert.Equal(4, builder.Count); - Assert.Equal(new[] { 7, 2, 3, 9 }, builder.Buffer.Take(4)); - } - - [Fact] - public void Insert_WhenBufferIsAtCapacity() - { - // Arrange - using var builder = CreateArrayBuilder(2); - builder.Append(new[] { 1, 3 }, 0, 2); - - // Act - builder.InsertExpensive(1, 2); - - // Assert - Assert.Equal(3, builder.Count); - Assert.Equal(new[] { 1, 2, 3 }, builder.Buffer.Take(3)); - } - - [Fact] - public void RemoveLast_Works() - { - // Arrange - using var builder = CreateArrayBuilder(); - builder.Append(1); - builder.Append(2); - builder.Append(3); - - // Act - builder.RemoveLast(); - - // Assert - Assert.Equal(2, builder.Count); - Assert.Equal(new[] { 1, 2, }, builder.Buffer.Take(2)); - } - - [Fact] - public void RemoveLast_LastEntry() - { - // Arrange - int[] buffer; - using (var builder = CreateArrayBuilder()) - { - builder.Append(1); - buffer = builder.Buffer; - - // Act - builder.RemoveLast(); - - // Assert - Assert.Equal(0, builder.Count); - } - - // Also verify that the buffer is indeed returned in this case. - var returnedBuffer = Assert.Single(ArrayPool.ReturnedBuffers); - Assert.Same(buffer, returnedBuffer); - } - - [Fact] - public void Clear_ReturnsBuffer() - { - // Arrange - using var builder = CreateArrayBuilder(); - builder.Append(1); - var buffer = builder.Buffer; - - // Act - builder.Clear(); - - // Assert - Assert.Equal(0, builder.Count); - var returnedBuffer = Assert.Single(ArrayPool.ReturnedBuffers); - Assert.Same(buffer, returnedBuffer); - } - - [Fact] - public void Dispose_WithEmptyBuffer_DoesNotReturnIt() - { - // Arrange - var builder = CreateArrayBuilder(); - - // Act - builder.Dispose(); - - // Assert - Assert.Empty(ArrayPool.ReturnedBuffers); - } - - [Fact] - public void Dispose_NonEmptyBufferIsReturned() - { - // Arrange - var builder = CreateArrayBuilder(); - builder.Append(1); - var buffer = builder.Buffer; - - // Act - builder.Dispose(); - - // Assert - Assert.Single(ArrayPool.ReturnedBuffers); - var returnedBuffer = Assert.Single(ArrayPool.ReturnedBuffers); - Assert.Same(buffer, returnedBuffer); - Assert.NotSame(builder.Buffer, buffer); // Prevents use after free - } - - [Fact] - public void DoubleDispose_DoesNotReturnBufferTwice() - { - // Arrange - var builder = CreateArrayBuilder(); - builder.Append(1); - var buffer = builder.Buffer; - - // Act - builder.Dispose(); - builder.Dispose(); - - // Assert - Assert.Single(ArrayPool.ReturnedBuffers); - var returnedBuffer = Assert.Single(ArrayPool.ReturnedBuffers); - Assert.Same(buffer, returnedBuffer); - } - - [Fact] - public void Dispose_ThrowsOnReuse() - { - // Arrange - var builder = CreateArrayBuilder(); - builder.Append(1); - var buffer = builder.Buffer; - - builder.Dispose(); - Assert.Single(ArrayPool.ReturnedBuffers); - - // Act & Assert - Assert.Throws(() => builder.Append(1)); - } - - [Fact] - public void UnusedBufferIsReturned_OnResize() - { - // Arrange - var builder = CreateArrayBuilder(2); - - // Act - for (var i = 0; i < 10; i++) - { - builder.Append(i); - } - - // Assert - Assert.Collection( - ArrayPool.ReturnedBuffers, - buffer => Assert.Equal(2, buffer.Length), - buffer => Assert.Equal(4, buffer.Length), - buffer => Assert.Equal(8, buffer.Length)); - - // Clear this because this is no longer interesting. - ArrayPool.ReturnedBuffers.Clear(); - - var buffer = builder.Buffer; - builder.Dispose(); - - Assert.Same(buffer, Assert.Single(ArrayPool.ReturnedBuffers)); - } - - private ArrayBuilder CreateArrayBuilder(int capacity = 32) - { - return new ArrayBuilder(capacity, ArrayPool); - } - } -} diff --git a/src/Components/Components/test/Rendering/RenderTreeBuilderTest.cs b/src/Components/Components/test/Rendering/RenderTreeBuilderTest.cs deleted file mode 100644 index 31364dca00..0000000000 --- a/src/Components/Components/test/Rendering/RenderTreeBuilderTest.cs +++ /dev/null @@ -1,1857 +0,0 @@ -// 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.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Components.RenderTree; -using Microsoft.AspNetCore.Components.Test.Helpers; -using Microsoft.Extensions.Logging.Abstractions; -using Moq; -using Xunit; - -namespace Microsoft.AspNetCore.Components.Rendering -{ - public class RenderTreeBuilderTest - { - [Fact] - public void StartsEmpty() - { - // Arrange - var builder = new RenderTreeBuilder(); - - // Assert - var frames = builder.GetFrames(); - Assert.NotNull(frames.Array); - Assert.Empty(frames.AsEnumerable()); - } - - [Fact] - public void CanAddText() - { - // Arrange - var builder = new RenderTreeBuilder(); - var nullString = (string)null; - - // Act - builder.AddContent(0, "First item"); - builder.AddContent(0, nullString); - builder.AddContent(0, "Second item"); - - // Assert - var frames = builder.GetFrames(); - Assert.Collection(frames.AsEnumerable(), - frame => AssertFrame.Text(frame, "First item"), - frame => AssertFrame.Text(frame, string.Empty), - frame => AssertFrame.Text(frame, "Second item")); - } - - [Fact] - public void CanAddMarkup() - { - // Arrange - var builder = new RenderTreeBuilder(); - - // Act - builder.OpenElement(0, "some elem"); - builder.AddMarkupContent(1, "Blah"); - builder.AddMarkupContent(2, string.Empty); - builder.CloseElement(); - - // Assert - var frames = builder.GetFrames(); - Assert.Collection(frames.AsEnumerable(), - frame => AssertFrame.Element(frame, "some elem", 3), - frame => AssertFrame.Markup(frame, "Blah"), - frame => AssertFrame.Markup(frame, string.Empty)); - } - - [Fact] - public void CanAddMarkupViaMarkupString() - { - // This represents putting @someMarkupString into the component, - // as opposed to calling builder.AddMarkupContent directly. - - // Arrange - var builder = new RenderTreeBuilder(); - - // Act - can use either constructor or cast - builder.AddContent(0, (MarkupString)"Some markup"); - builder.AddContent(1, new MarkupString(null)); - - // Assert - var frames = builder.GetFrames(); - Assert.Collection(frames.AsEnumerable(), - frame => AssertFrame.Markup(frame, "Some markup"), - frame => AssertFrame.Markup(frame, string.Empty)); - } - - [Fact] - public void CanAddNullMarkup() - { - // Arrange - var builder = new RenderTreeBuilder(); - - // Act - builder.AddMarkupContent(0, null); - - // Assert - var frames = builder.GetFrames(); - Assert.Collection(frames.AsEnumerable(), - frame => AssertFrame.Markup(frame, string.Empty)); - } - - [Fact] - public void CanAddNonStringValueAsText() - { - // Arrange - var builder = new RenderTreeBuilder(); - var nullObject = (object)null; - - // Act - builder.AddContent(0, 1234); - builder.AddContent(0, nullObject); - - // Assert - var frames = builder.GetFrames(); - Assert.Collection(frames.AsEnumerable(), - frame => AssertFrame.Text(frame, "1234"), - frame => AssertFrame.Text(frame, string.Empty)); - } - - [Fact] - public void UnclosedElementsHaveNoSubtreeLength() - { - // Arrange - var builder = new RenderTreeBuilder(); - - // Act - builder.OpenElement(0, "my element"); - - // Assert - var frame = builder.GetFrames().AsEnumerable().Single(); - AssertFrame.Element(frame, "my element", 0); - } - - [Fact] - public void ClosedEmptyElementsHaveSubtreeLengthOne() - { - // Arrange - var builder = new RenderTreeBuilder(); - - // Act - builder.AddContent(0, "some frame so that the element isn't at position zero"); - builder.OpenElement(0, "my element"); - builder.CloseElement(); - - // Assert - var frames = builder.GetFrames(); - Assert.Equal(2, frames.Count); - AssertFrame.Element(frames.Array[1], "my element", 1); - } - - [Fact] - public void ClosedElementsHaveCorrectSubtreeLength() - { - // Arrange - var builder = new RenderTreeBuilder(); - - // Act - builder.OpenElement(0, "my element"); - builder.AddContent(0, "child 1"); - builder.AddContent(0, "child 2"); - builder.CloseElement(); - builder.AddContent(0, "unrelated item"); - - // Assert - var frames = builder.GetFrames(); - Assert.Equal(4, frames.Count); - AssertFrame.Element(frames.Array[0], "my element", 3); - } - - [Fact] - public void CanNestElements() - { - // Arrange - var builder = new RenderTreeBuilder(); - - // Act - builder.AddContent(0, "standalone text 1"); // 0: standalone text 1 - builder.OpenElement(0, "root"); // 1: - builder.AddContent(0, "root text 1"); // 2: root text 1 - builder.AddContent(0, "root text 2"); // 3: root text 2 - builder.OpenElement(0, "child"); // 4: - builder.AddContent(0, "child text"); // 5: child text - builder.OpenElement(0, "grandchild"); // 6: - builder.AddContent(0, "grandchild text 1"); // 7: grandchild text 1 - builder.AddContent(0, "grandchild text 2"); // 8: grandchild text 2 - builder.CloseElement(); // - builder.CloseElement(); // - builder.AddContent(0, "root text 3"); // 9: root text 3 - builder.OpenElement(0, "child 2"); // 10: - builder.CloseElement(); // - builder.CloseElement(); // - builder.AddContent(0, "standalone text 2"); // 11: standalone text 2 - - // Assert - Assert.Collection(builder.GetFrames().AsEnumerable(), - frame => AssertFrame.Text(frame, "standalone text 1"), - frame => AssertFrame.Element(frame, "root", 10), - frame => AssertFrame.Text(frame, "root text 1"), - frame => AssertFrame.Text(frame, "root text 2"), - frame => AssertFrame.Element(frame, "child", 5), - frame => AssertFrame.Text(frame, "child text"), - frame => AssertFrame.Element(frame, "grandchild", 3), - frame => AssertFrame.Text(frame, "grandchild text 1"), - frame => AssertFrame.Text(frame, "grandchild text 2"), - frame => AssertFrame.Text(frame, "root text 3"), - frame => AssertFrame.Element(frame, "child 2", 1), - frame => AssertFrame.Text(frame, "standalone text 2")); - } - - [Fact] - public void CanAddAttributes() - { - // Arrange - var builder = new RenderTreeBuilder(); - Action eventHandler = eventInfo => { }; - - // Act - builder.OpenElement(0, "myelement"); // 0: - builder.OpenElement(0, "child"); // 3: - builder.AddContent(0, "some text"); // 5: some text - builder.CloseElement(); // - builder.CloseElement(); // - - // Assert - Assert.Collection(builder.GetFrames().AsEnumerable(), - frame => AssertFrame.Element(frame, "myelement", 6), - frame => AssertFrame.Attribute(frame, "attribute1", "value 1"), - frame => AssertFrame.Attribute(frame, "attribute2", "123"), - frame => AssertFrame.Element(frame, "child", 3), - frame => AssertFrame.Attribute(frame, "childevent", eventHandler), - frame => AssertFrame.Text(frame, "some text")); - } - - [Fact] - public void CanAddMultipleAttributes_AllowsNull() - { - // Arrange - var builder = new RenderTreeBuilder(); - - // Act - builder.OpenElement(0, "myelement"); - builder.AddMultipleAttributes(0, null); - builder.CloseElement(); - - // Assert - var frames = builder.GetFrames().AsEnumerable().ToArray(); - Assert.Collection( - frames, - frame => AssertFrame.Element(frame, "myelement", 1)); - } - - [Fact] - public void CanAddMultipleAttributes_InterspersedWithOtherAttributes() - { - // Arrange - var builder = new RenderTreeBuilder(); - Action eventHandler = eventInfo => { }; - - // Act - builder.OpenElement(0, "myelement"); - builder.AddAttribute(0, "attribute1", "value 1"); - builder.AddMultipleAttributes(0, new Dictionary(StringComparer.OrdinalIgnoreCase) - { - { "attribute1", "test1" }, - { "attribute2", true }, - { "attribute3", eventHandler }, - }); - builder.AddAttribute(0, "ATTRIBUTE2", true); - builder.AddMultipleAttributes(0, new Dictionary(StringComparer.OrdinalIgnoreCase) - { - { "attribute4", "test4" }, - { "attribute5", false }, - { "attribute6", eventHandler }, - }); - - // Null or false values don't create frames of their own, but they can - // "knock out" earlier values. - builder.AddAttribute(0, "attribute6", false); - builder.AddAttribute(0, "attribute4", (string)null); - - builder.AddAttribute(0, "attribute7", "the end"); - builder.CloseElement(); - - // Assert - var frames = builder.GetFrames().AsEnumerable().ToArray(); - Assert.Collection( - frames, - frame => AssertFrame.Element(frame, "myelement", 5), - frame => AssertFrame.Attribute(frame, "attribute1", "test1"), - frame => AssertFrame.Attribute(frame, "attribute3", eventHandler), - frame => AssertFrame.Attribute(frame, "ATTRIBUTE2", true), - frame => AssertFrame.Attribute(frame, "attribute7", "the end")); - } - - [Fact] - public void CanAddMultipleAttributes_WithChildRegion() - { - // This represents bug https://github.com/aspnet/AspNetCore/issues/16570 - // If a sequence of attributes is terminated by a call to builder.OpenRegion, - // then the attribute deduplication logic wasn't working correctly - - // Arrange - var builder = new RenderTreeBuilder(); - - // Act - builder.OpenElement(0, "myelement"); - builder.AddAttribute(0, "attribute1", "value1"); - builder.AddMultipleAttributes(1, new Dictionary() - { - { "attribute1", "value2" }, - }); - builder.OpenRegion(2); - builder.OpenElement(3, "child"); - builder.CloseElement(); - builder.CloseRegion(); - builder.CloseElement(); - - // Assert - var frames = builder.GetFrames().AsEnumerable().ToArray(); - Assert.Collection( - frames, - frame => AssertFrame.Element(frame, "myelement", 4), - frame => AssertFrame.Attribute(frame, "attribute1", "value2"), - frame => AssertFrame.Region(frame, 2, 2), - frame => AssertFrame.Element(frame, "child", 1, 3)); - } - - [Fact] - public void CanAddMultipleAttributes_DictionaryObject() - { - var attributes = new Dictionary - { - { "attribute1", "test1" }, - { "attribute2", "123" }, - { "attribute3", true }, - }; - - // Act & Assert - CanAddMultipleAttributesTest(attributes); - } - - [Fact] - public void CanAddMultipleAttributes_IReadOnlyDictionaryObject() - { - var attributes = new Dictionary - { - { "attribute1", "test1" }, - { "attribute2", "123" }, - { "attribute3", true }, - }; - - // Act & Assert - CanAddMultipleAttributesTest((IReadOnlyDictionary)attributes); - } - - [Fact] - public void CanAddMultipleAttributes_ListKvpObject() - { - var attributes = new List>() - { - new KeyValuePair("attribute1", "test1"), - new KeyValuePair("attribute2", "123"), - new KeyValuePair("attribute3", true), - }; - - // Act & Assert - CanAddMultipleAttributesTest(attributes); - } - - [Fact] - public void CanAddMultipleAttributes_ArrayKvpObject() - { - var attributes = new KeyValuePair[] - { - new KeyValuePair("attribute1", "test1"), - new KeyValuePair("attribute2", "123"), - new KeyValuePair("attribute3", true), - }; - - // Act & Assert - CanAddMultipleAttributesTest(attributes); - } - - private void CanAddMultipleAttributesTest(IEnumerable> attributes) - { - // Arrange - var builder = new RenderTreeBuilder(); - - // Act - builder.OpenElement(0, "myelement"); - builder.AddMultipleAttributes(0, attributes); - builder.CloseElement(); - - // Assert - var frames = builder.GetFrames().AsEnumerable().ToArray(); - - var i = 1; - foreach (var attribute in attributes) - { - var frame = frames[i++]; - AssertFrame.Attribute(frame, attribute.Key, attribute.Value); - } - } - - [Fact] - public void CannotAddAttributeAtRoot() - { - // Arrange - var builder = new RenderTreeBuilder(); - - // Act/Assert - Assert.Throws(() => - { - builder.AddAttribute(0, "name", "value"); - }); - } - - [Fact] - public void CannotAddDelegateAttributeAtRoot() - { - // Arrange - var builder = new RenderTreeBuilder(); - - // Act/Assert - Assert.Throws(() => - { - builder.AddAttribute(0, "name", new Action(text => { })); - }); - } - - [Fact] - public void CannotAddAttributeToText() - { - // Arrange - var builder = new RenderTreeBuilder(); - - // Act/Assert - Assert.Throws(() => - { - builder.OpenElement(0, "some element"); - builder.AddContent(1, "hello"); - builder.AddAttribute(2, "name", "value"); - }); - } - - [Fact] - public void CannotAddEventHandlerAttributeToText() - { - // Arrange - var builder = new RenderTreeBuilder(); - - // Act/Assert - Assert.Throws(() => - { - builder.OpenElement(0, "some element"); - builder.AddContent(1, "hello"); - builder.AddAttribute(2, "name", new Action(eventInfo => { })); - }); - } - - [Fact] - public void CannotAddAttributeToRegion() - { - // Arrange - var builder = new RenderTreeBuilder(); - - // Act/Assert - Assert.Throws(() => - { - builder.OpenRegion(0); - builder.AddAttribute(1, "name", "value"); - }); - } - - [Fact] - public void CannotAddAttributeToElementReferenceCapture() - { - // Arrange - var builder = new RenderTreeBuilder(); - - // Act/Assert - Assert.Throws(() => - { - builder.OpenElement(0, "some element"); - builder.AddElementReferenceCapture(1, _ => { }); - builder.AddAttribute(2, "name", "value"); - }); - } - - [Fact] - public void CannotAddAttributeToComponentReferenceCapture() - { - // Arrange - var builder = new RenderTreeBuilder(); - - // Act/Assert - Assert.Throws(() => - { - builder.OpenComponent(0); - builder.AddComponentReferenceCapture(1, _ => { }); - builder.AddAttribute(2, "name", "value"); - }); - } - - [Fact] - public void CanAddChildComponentsUsingGenericParam() - { - // Arrange - var builder = new RenderTreeBuilder(); - - // Act - builder.OpenElement(10, "parent"); // 0: - builder.OpenComponent(11); // 1: - builder.CloseComponent(); // - builder.OpenComponent(14); // 4: - builder.CloseComponent(); // - builder.CloseElement(); // - - // Assert - Assert.Collection(builder.GetFrames().AsEnumerable(), - frame => AssertFrame.Element(frame, "parent", 6), - frame => AssertFrame.Component(frame), - frame => AssertFrame.Attribute(frame, "child1attribute1", "A"), - frame => AssertFrame.Attribute(frame, "child1attribute2", "B"), - frame => AssertFrame.Component(frame), - frame => AssertFrame.Attribute(frame, "child2attribute", "C")); - } - - [Fact] - public void CanAddChildComponentsUsingTypeArgument() - { - // Arrange - var builder = new RenderTreeBuilder(); - - // Act - var componentType = typeof(TestComponent); - builder.OpenElement(10, "parent"); // 0: - builder.OpenComponent(11, componentType); // 1: - builder.CloseComponent(); // - builder.OpenComponent(14, componentType); // 4: - builder.CloseComponent(); // - builder.CloseElement(); // - - // Assert - Assert.Collection(builder.GetFrames().AsEnumerable(), - frame => AssertFrame.Element(frame, "parent", 6), - frame => AssertFrame.Component(frame), - frame => AssertFrame.Attribute(frame, "child1attribute1", "A"), - frame => AssertFrame.Attribute(frame, "child1attribute2", "B"), - frame => AssertFrame.Component(frame), - frame => AssertFrame.Attribute(frame, "child2attribute", "C")); - } - - [Fact] - public void CanAddRegions() - { - // Arrange - var builder = new RenderTreeBuilder(); - - // Act - builder.OpenElement(10, "parent"); // 0: - builder.OpenRegion(11); // 1: [region - builder.AddContent(3, "Hello"); // 2: Hello - builder.OpenRegion(4); // 3: [region - builder.OpenElement(3, "another"); // 4: - builder.CloseElement(); // - builder.CloseRegion(); // ] - builder.AddContent(6, "Goodbye"); // 5: Goodbye - builder.CloseRegion(); // ] - builder.CloseElement(); // - - // Assert - Assert.Collection(builder.GetFrames().AsEnumerable(), - frame => AssertFrame.Element(frame, "parent", 6, 10), - frame => AssertFrame.Region(frame, 5, 11), - frame => AssertFrame.Text(frame, "Hello", 3), - frame => AssertFrame.Region(frame, 2, 4), - frame => AssertFrame.Element(frame, "another", 1, 3), - frame => AssertFrame.Text(frame, "Goodbye", 6)); - } - - [Fact] - public void CanAddFragments() - { - // Arrange - var builder = new RenderTreeBuilder(); - RenderFragment fragment = fragmentBuilder => - { - fragmentBuilder.AddContent(0, "Hello from the fragment"); - fragmentBuilder.OpenElement(1, "Fragment element"); - fragmentBuilder.AddContent(2, "Some text"); - fragmentBuilder.CloseElement(); - }; - - // Act - builder.OpenElement(10, "parent"); - builder.AddContent(11, fragment); - builder.CloseElement(); - - // Assert - Assert.Collection(builder.GetFrames().AsEnumerable(), - frame => AssertFrame.Element(frame, "parent", 5, 10), - frame => AssertFrame.Region(frame, 4, 11), - frame => AssertFrame.Text(frame, "Hello from the fragment", 0), - frame => AssertFrame.Element(frame, "Fragment element", 2, 1), - frame => AssertFrame.Text(frame, "Some text", 2)); - } - - [Fact] - public void CanAddElementReferenceCaptureInsideElement() - { - // Arrange - var builder = new RenderTreeBuilder(); - Action referenceCaptureAction = elementReference => { }; - - // Act - builder.OpenElement(0, "myelement"); // 0: - builder.AddElementReferenceCapture(2, referenceCaptureAction); // 2: # capture: referenceCaptureAction - builder.AddContent(3, "some text"); // 3: some text - builder.CloseElement(); // - - // Assert - Assert.Collection(builder.GetFrames().AsEnumerable(), - frame => AssertFrame.Element(frame, "myelement", 4, 0), - frame => AssertFrame.Attribute(frame, "attribute2", "123", 1), - frame => AssertFrame.ElementReferenceCapture(frame, referenceCaptureAction, 2), - frame => AssertFrame.Text(frame, "some text", 3)); - } - - [Fact] - public void CannotAddElementReferenceCaptureWithNoParent() - { - // Arrange - var builder = new RenderTreeBuilder(); - - // Act/Assert - Assert.Throws(() => - { - builder.AddElementReferenceCapture(0, _ => { }); - }); - } - - [Fact] - public void CannotAddElementReferenceCaptureInsideComponent() - { - // Arrange - var builder = new RenderTreeBuilder(); - - // Act/Assert - Assert.Throws(() => - { - builder.OpenComponent(0); - builder.AddElementReferenceCapture(1, _ => { }); - }); - } - - [Fact] - public void CannotAddElementReferenceCaptureInsideRegion() - { - // Arrange - var builder = new RenderTreeBuilder(); - - // Act/Assert - Assert.Throws(() => - { - builder.OpenRegion(0); - builder.AddElementReferenceCapture(1, _ => { }); - }); - } - - [Fact] - public void CanAddMultipleReferenceCapturesToSameElement() - { - // There won't be any way of doing this from Razor because there's no known use - // case for it. However it's harder to *not* support it than to support it, and - // there's no known reason to prevent it, so here's test coverage to show it - // just works. - - // Arrange - var builder = new RenderTreeBuilder(); - Action referenceCaptureAction1 = elementReference => { }; - Action referenceCaptureAction2 = elementReference => { }; - - // Act - builder.OpenElement(0, "myelement"); - builder.AddElementReferenceCapture(0, referenceCaptureAction1); - builder.AddElementReferenceCapture(0, referenceCaptureAction2); - builder.CloseElement(); - - // Assert - Assert.Collection(builder.GetFrames().AsEnumerable(), - frame => AssertFrame.Element(frame, "myelement", 3), - frame => AssertFrame.ElementReferenceCapture(frame, referenceCaptureAction1), - frame => AssertFrame.ElementReferenceCapture(frame, referenceCaptureAction2)); - } - - [Fact] - public void CanAddComponentReferenceCaptureInsideComponent() - { - // Arrange - var builder = new RenderTreeBuilder(); - Action myAction = elementReference => { }; - - // Act - builder.OpenComponent(0); // 0: - builder.AddComponentReferenceCapture(2, myAction); // 2: # capture: myAction - builder.AddContent(3, "some text"); // 3: some text - builder.CloseComponent(); // - - // Assert - Assert.Collection(builder.GetFrames().AsEnumerable(), - frame => AssertFrame.Component(frame, 4, 0), - frame => AssertFrame.Attribute(frame, "attribute2", 123, 1), - frame => AssertFrame.ComponentReferenceCapture(frame, myAction, 2), - frame => AssertFrame.Text(frame, "some text", 3)); - } - - [Fact] - public void CannotAddComponentReferenceCaptureWithNoParent() - { - // Arrange - var builder = new RenderTreeBuilder(); - - // Act/Assert - Assert.Throws(() => - { - builder.AddComponentReferenceCapture(0, _ => { }); - }); - } - - [Fact] - public void CannotAddComponentReferenceCaptureInsideElement() - { - // Arrange - var builder = new RenderTreeBuilder(); - - // Act/Assert - Assert.Throws(() => - { - builder.OpenElement(0, "myelement"); - builder.AddComponentReferenceCapture(1, _ => { }); - }); - } - - [Fact] - public void CannotAddComponentReferenceCaptureInsideRegion() - { - // Arrange - var builder = new RenderTreeBuilder(); - - // Act/Assert - Assert.Throws(() => - { - builder.OpenRegion(0); - builder.AddComponentReferenceCapture(1, _ => { }); - }); - } - - [Fact] - public void CanAddMultipleReferenceCapturesToSameComponent() - { - // There won't be any way of doing this from Razor because there's no known use - // case for it. However it's harder to *not* support it than to support it, and - // there's no known reason to prevent it, so here's test coverage to show it - // just works. - - // Arrange - var builder = new RenderTreeBuilder(); - Action referenceCaptureAction1 = elementReference => { }; - Action referenceCaptureAction2 = elementReference => { }; - - // Act - builder.OpenComponent(0); - builder.AddComponentReferenceCapture(0, referenceCaptureAction1); - builder.AddComponentReferenceCapture(0, referenceCaptureAction2); - builder.CloseComponent(); - - // Assert - Assert.Collection(builder.GetFrames().AsEnumerable(), - frame => AssertFrame.Component(frame, 3), - frame => AssertFrame.ComponentReferenceCapture(frame, referenceCaptureAction1), - frame => AssertFrame.ComponentReferenceCapture(frame, referenceCaptureAction2)); - } - - [Fact] - public void CanClear() - { - // Arrange - var builder = new RenderTreeBuilder(); - - // Act - builder.AddContent(0, "some text"); - builder.OpenElement(1, "elem"); - builder.AddContent(2, "more text"); - builder.CloseElement(); - builder.Clear(); - - // Assert - Assert.Empty(builder.GetFrames().AsEnumerable()); - } - - [Fact] - public void AddAttribute_Element_BoolTrue_AddsFrame() - { - // Arrange - var builder = new RenderTreeBuilder(); - - // Act - builder.OpenElement(0, "elem"); - builder.AddAttribute(1, "attr", true); - builder.CloseElement(); - - // Assert - Assert.Collection( - builder.GetFrames().AsEnumerable(), - frame => AssertFrame.Element(frame, "elem", 2, 0), - frame => AssertFrame.Attribute(frame, "attr", true, 1)); - } - - [Fact] - public void AddAttribute_Element_BoolFalse_IgnoresFrame() - { - // Arrange - var builder = new RenderTreeBuilder(); - - // Act - builder.OpenElement(0, "elem"); - builder.AddAttribute(1, "attr", false); - builder.CloseElement(); - - // Assert - Assert.Collection( - builder.GetFrames().AsEnumerable(), - frame => AssertFrame.Element(frame, "elem", 1, 0)); - } - - [Theory] - [InlineData(false)] - [InlineData(true)] - public void AddAttribute_Component_Bool_SetsAttributeValue(bool value) - { - // Arrange - var builder = new RenderTreeBuilder(); - - // Act - builder.OpenComponent(0); - builder.AddAttribute(1, "attr", value); - builder.CloseComponent(); - - // Assert - Assert.Collection( - builder.GetFrames().AsEnumerable(), - frame => AssertFrame.Component(frame, 2, 0), - frame => AssertFrame.Attribute(frame, "attr", value, 1)); - } - - [Fact] - public void AddAttribute_Element_StringValue_AddsFrame() - { - // Arrange - var builder = new RenderTreeBuilder(); - - // Act - builder.OpenElement(0, "elem"); - builder.AddAttribute(1, "attr", "hi"); - builder.CloseElement(); - - // Assert - Assert.Collection( - builder.GetFrames().AsEnumerable(), - frame => AssertFrame.Element(frame, "elem", 2, 0), - frame => AssertFrame.Attribute(frame, "attr", "hi", 1)); - } - - [Fact] - public void AddAttribute_Element_StringNull_IgnoresFrame() - { - // Arrange - var builder = new RenderTreeBuilder(); - - // Act - builder.OpenElement(0, "elem"); - builder.AddAttribute(1, "attr", (string)null); - builder.CloseElement(); - - // Assert - Assert.Collection( - builder.GetFrames().AsEnumerable(), - frame => AssertFrame.Element(frame, "elem", 1, 0)); - } - - [Theory] - [InlineData("hi")] - [InlineData(null)] - public void AddAttribute_Component_StringValue_SetsAttributeValue(string value) - { - // Arrange - var builder = new RenderTreeBuilder(); - - // Act - builder.OpenComponent(0); - builder.AddAttribute(1, "attr", value); - builder.CloseComponent(); - - // Assert - Assert.Collection( - builder.GetFrames().AsEnumerable(), - frame => AssertFrame.Component(frame, 2, 0), - frame => AssertFrame.Attribute(frame, "attr", value, 1)); - } - - [Fact] - public void AddAttribute_Element_EventHandler_AddsFrame() - { - // Arrange - var builder = new RenderTreeBuilder(); - - var value = new Action((e) => { }); - - // Act - builder.OpenElement(0, "elem"); - builder.AddAttribute(1, "attr", value); - builder.CloseElement(); - - // Assert - Assert.Collection( - builder.GetFrames().AsEnumerable(), - frame => AssertFrame.Element(frame, "elem", 2, 0), - frame => AssertFrame.Attribute(frame, "attr", value, 1)); - } - - [Fact] - public void AddAttribute_Element_NullEventHandler_IgnoresFrame() - { - // Arrange - var builder = new RenderTreeBuilder(); - - // Act - builder.OpenElement(0, "elem"); - builder.AddAttribute(1, "attr", (Action)null); - builder.CloseElement(); - - // Assert - Assert.Collection( - builder.GetFrames().AsEnumerable(), - frame => AssertFrame.Element(frame, "elem", 1, 0)); - } - - [Fact] - public void AddAttribute_Element_Action_AddsFrame() - { - // Arrange - var builder = new RenderTreeBuilder(); - - var value = new Action(() => { }); - - // Act - builder.OpenElement(0, "elem"); - builder.AddAttribute(1, "attr", value); - builder.CloseElement(); - - // Assert - Assert.Collection( - builder.GetFrames().AsEnumerable(), - frame => AssertFrame.Element(frame, "elem", 2, 0), - frame => AssertFrame.Attribute(frame, "attr", value, 1)); - } - - [Fact] - public void AddAttribute_Element_NullAction_IgnoresFrame() - { - // Arrange - var builder = new RenderTreeBuilder(); - - // Act - builder.OpenElement(0, "elem"); - builder.AddAttribute(1, "attr", (Action)null); - builder.CloseElement(); - - // Assert - Assert.Collection( - builder.GetFrames().AsEnumerable(), - frame => AssertFrame.Element(frame, "elem", 1, 0)); - } - - public static TheoryData> EventHandlerValues => new TheoryData> - { - null, - (e) => { }, - }; - - [Theory] - [MemberData(nameof(EventHandlerValues))] - public void AddAttribute_Component_EventHandlerValue_SetsAttributeValue(Action value) - { - // Arrange - var builder = new RenderTreeBuilder(); - - // Act - builder.OpenComponent(0); - builder.AddAttribute(1, "attr", value); - builder.CloseComponent(); - - // Assert - Assert.Collection( - builder.GetFrames().AsEnumerable(), - frame => AssertFrame.Component(frame, 2, 0), - frame => AssertFrame.Attribute(frame, "attr", value, 1)); - } - - [Fact] - public void AddAttribute_Element_EventCallback_AddsFrame() - { - // Arrange - var builder = new RenderTreeBuilder(); - var callback = new EventCallback(null, new Action(() => { })); - - // Act - builder.OpenElement(0, "elem"); - builder.AddAttribute(1, "attr", callback); - builder.CloseElement(); - - // Assert - Assert.Collection( - builder.GetFrames().AsEnumerable(), - frame => AssertFrame.Element(frame, "elem", 2, 0), - frame => AssertFrame.Attribute(frame, "attr", callback.Delegate, 1)); - } - - [Fact] - public void AddAttribute_Element_EventCallback_Default_DoesNotAddFrame() - { - // Arrange - var builder = new RenderTreeBuilder(); - var callback = default(EventCallback); - - // Act - builder.OpenElement(0, "elem"); - builder.AddAttribute(1, "attr", callback); - builder.CloseElement(); - - // Assert - Assert.Collection( - builder.GetFrames().AsEnumerable(), - frame => AssertFrame.Element(frame, "elem", 1, 0)); - } - - [Fact] - public void AddAttribute_Element_EventCallbackWithReceiver_AddsFrame() - { - // Arrange - var builder = new RenderTreeBuilder(); - var receiver = Mock.Of(); - var callback = new EventCallback(receiver, new Action(() => { })); - - // Act - builder.OpenElement(0, "elem"); - builder.AddAttribute(1, "attr", callback); - builder.CloseElement(); - - // Assert - Assert.Collection( - builder.GetFrames().AsEnumerable(), - frame => AssertFrame.Element(frame, "elem", 2, 0), - frame => AssertFrame.Attribute(frame, "attr", callback, 1)); - } - - [Fact] - public void AddAttribute_Component_EventCallback_AddsFrame() - { - // Arrange - var builder = new RenderTreeBuilder(); - var receiver = Mock.Of(); - var callback = new EventCallback(receiver, new Action(() => { })); - - // Act - builder.OpenComponent(0); - builder.AddAttribute(1, "attr", callback); - builder.CloseComponent(); - - // Assert - Assert.Collection( - builder.GetFrames().AsEnumerable(), - frame => AssertFrame.Component(frame, 2, 0), - frame => AssertFrame.Attribute(frame, "attr", callback, 1)); - } - - [Fact] - public void AddAttribute_Element_EventCallbackOfT_AddsFrame() - { - // Arrange - var builder = new RenderTreeBuilder(); - var callback = new EventCallback(null, new Action((s) => { })); - - // Act - builder.OpenElement(0, "elem"); - builder.AddAttribute(1, "attr", callback); - builder.CloseElement(); - - // Assert - Assert.Collection( - builder.GetFrames().AsEnumerable(), - frame => AssertFrame.Element(frame, "elem", 2, 0), - frame => AssertFrame.Attribute(frame, "attr", callback.Delegate, 1)); - } - - [Fact] - public void AddAttribute_Element_EventCallbackOfT_Default_DoesNotAddFrame() - { - // Arrange - var builder = new RenderTreeBuilder(); - var callback = default(EventCallback); - - // Act - builder.OpenElement(0, "elem"); - builder.AddAttribute(1, "attr", callback); - builder.CloseElement(); - - // Assert - Assert.Collection( - builder.GetFrames().AsEnumerable(), - frame => AssertFrame.Element(frame, "elem", 1, 0)); - } - - [Fact] - public void AddAttribute_Element_EventCallbackWithReceiverOfT_AddsFrame() - { - // Arrange - var builder = new RenderTreeBuilder(); - var receiver = Mock.Of(); - var callback = new EventCallback(receiver, new Action((s) => { })); - - // Act - builder.OpenElement(0, "elem"); - builder.AddAttribute(1, "attr", callback); - builder.CloseElement(); - - // Assert - Assert.Collection( - builder.GetFrames().AsEnumerable(), - frame => AssertFrame.Element(frame, "elem", 2, 0), - frame => AssertFrame.Attribute(frame, "attr", new EventCallback(callback.Receiver, callback.Delegate), 1)); - } - - [Fact] - public void AddAttribute_Component_EventCallbackOfT_AddsFrame() - { - // Arrange - var builder = new RenderTreeBuilder(); - var receiver = Mock.Of(); - var callback = new EventCallback(receiver, new Action((s) => { })); - - // Act - builder.OpenComponent(0); - builder.AddAttribute(1, "attr", callback); - builder.CloseComponent(); - - // Assert - Assert.Collection( - builder.GetFrames().AsEnumerable(), - frame => AssertFrame.Component(frame, 2, 0), - frame => AssertFrame.Attribute(frame, "attr", callback, 1)); - } - - [Fact] - public void AddAttribute_Element_ObjectBoolTrue_AddsFrame() - { - // Arrange - var builder = new RenderTreeBuilder(); - - // Act - builder.OpenElement(0, "elem"); - builder.AddAttribute(1, "attr", (object)true); - builder.CloseElement(); - - // Assert - Assert.Collection( - builder.GetFrames().AsEnumerable(), - frame => AssertFrame.Element(frame, "elem", 2, 0), - frame => AssertFrame.Attribute(frame, "attr", true, 1)); - } - - [Fact] - public void AddAttribute_Element_ObjectBoolFalse_IgnoresFrame() - { - // Arrange - var builder = new RenderTreeBuilder(); - - // Act - builder.OpenElement(0, "elem"); - builder.AddAttribute(1, "attr", (object)false); - builder.CloseElement(); - - // Assert - Assert.Collection( - builder.GetFrames().AsEnumerable(), - frame => AssertFrame.Element(frame, "elem", 1, 0)); - } - - [Theory] - [InlineData(false)] - [InlineData(true)] - public void AddAttribute_Component_ObjectBoolValue_SetsAttributeValue(bool value) - { - // Arrange - var builder = new RenderTreeBuilder(); - - // Act - builder.OpenComponent(0); - builder.AddAttribute(1, "attr", (object)value); - builder.CloseComponent(); - - // Assert - Assert.Collection( - builder.GetFrames().AsEnumerable(), - frame => AssertFrame.Component(frame, 2, 0), - frame => AssertFrame.Attribute(frame, "attr", value, 1)); - } - - [Fact] - public void AddAttribute_Element_ObjectStringValue_AddsFrame() - { - // Arrange - var builder = new RenderTreeBuilder(); - - // Act - builder.OpenElement(0, "elem"); - builder.AddAttribute(1, "attr", (object)"hi"); - builder.CloseElement(); - - // Assert - Assert.Collection( - builder.GetFrames().AsEnumerable(), - frame => AssertFrame.Element(frame, "elem", 2, 0), - frame => AssertFrame.Attribute(frame, "attr", "hi", 1)); - } - - [Fact] - public void AddAttribute_Component_ObjectStringValue_SetsAttributeValue() - { - // Arrange - var builder = new RenderTreeBuilder(); - - // Act - builder.OpenComponent(0); - builder.AddAttribute(1, "attr", (object)"hi"); - builder.CloseComponent(); - - // Assert - Assert.Collection( - builder.GetFrames().AsEnumerable(), - frame => AssertFrame.Component(frame, 2, 0), - frame => AssertFrame.Attribute(frame, "attr", "hi", 1)); - } - - [Fact] - public void AddAttribute_Element_ObjectEventHandler_AddsFrame() - { - // Arrange - var builder = new RenderTreeBuilder(); - - var value = new Action((e) => { }); - - // Act - builder.OpenElement(0, "elem"); - builder.AddAttribute(1, "attr", (object)value); - builder.CloseElement(); - - // Assert - Assert.Collection( - builder.GetFrames().AsEnumerable(), - frame => AssertFrame.Element(frame, "elem", 2, 0), - frame => AssertFrame.Attribute(frame, "attr", value, 1)); - } - - [Fact] - public void AddAttribute_Component_ObjectUIEventHandleValue_SetsAttributeValue() - { - // Arrange - var builder = new RenderTreeBuilder(); - - var value = new Action((e) => { }); - - // Act - builder.OpenComponent(0); - builder.AddAttribute(1, "attr", (object)value); - builder.CloseComponent(); - - // Assert - Assert.Collection( - builder.GetFrames().AsEnumerable(), - frame => AssertFrame.Component(frame, 2, 0), - frame => AssertFrame.Attribute(frame, "attr", value, 1)); - } - - [Fact] - public void AddAttribute_Element_ObjectAction_AddsFrame() - { - // Arrange - var builder = new RenderTreeBuilder(); - - var value = new Action(() => { }); - - // Act - builder.OpenElement(0, "elem"); - builder.AddAttribute(1, "attr", (object)value); - builder.CloseElement(); - - // Assert - Assert.Collection( - builder.GetFrames().AsEnumerable(), - frame => AssertFrame.Element(frame, "elem", 2, 0), - frame => AssertFrame.Attribute(frame, "attr", value, 1)); - } - - [Fact] - public void AddAttribute_Component_ObjectAction_SetsAttributeValue() - { - // Arrange - var builder = new RenderTreeBuilder(); - - var value = new Action(() => { }); - - // Act - builder.OpenComponent(0); - builder.AddAttribute(1, "attr", (object)value); - builder.CloseComponent(); - - // Assert - Assert.Collection( - builder.GetFrames().AsEnumerable(), - frame => AssertFrame.Component(frame, 2, 0), - frame => AssertFrame.Attribute(frame, "attr", value, 1)); - } - - [Fact] - public void AddAttribute_Element_ObjectEventCallback_AddsFrame() - { - // Arrange - var builder = new RenderTreeBuilder(); - var callback = new EventCallback(null, new Action(() => { })); - - // Act - builder.OpenElement(0, "elem"); - builder.AddAttribute(1, "attr", (object)callback); - builder.CloseElement(); - - // Assert - Assert.Collection( - builder.GetFrames().AsEnumerable(), - frame => AssertFrame.Element(frame, "elem", 2, 0), - frame => AssertFrame.Attribute(frame, "attr", callback.Delegate, 1)); - } - - [Fact] - public void AddAttribute_Element_ObjectEventCallback_Default_DoesNotAddFrame() - { - // Arrange - var builder = new RenderTreeBuilder(); - var callback = default(EventCallback); - - // Act - builder.OpenElement(0, "elem"); - builder.AddAttribute(1, "attr", (object)callback); - builder.CloseElement(); - - // Assert - Assert.Collection( - builder.GetFrames().AsEnumerable(), - frame => AssertFrame.Element(frame, "elem", 1, 0)); - } - - [Fact] - public void AddAttribute_Element_ObjectEventCallbackWithReceiver_AddsFrame() - { - // Arrange - var builder = new RenderTreeBuilder(); - var receiver = Mock.Of(); - var callback = new EventCallback(receiver, new Action(() => { })); - - // Act - builder.OpenElement(0, "elem"); - builder.AddAttribute(1, "attr", (object)callback); - builder.CloseElement(); - - // Assert - Assert.Collection( - builder.GetFrames().AsEnumerable(), - frame => AssertFrame.Element(frame, "elem", 2, 0), - frame => AssertFrame.Attribute(frame, "attr", callback, 1)); - } - - [Fact] - public void AddAttribute_Component_ObjectEventCallback_AddsFrame() - { - // Arrange - var builder = new RenderTreeBuilder(); - var receiver = Mock.Of(); - var callback = new EventCallback(receiver, new Action(() => { })); - - // Act - builder.OpenComponent(0); - builder.AddAttribute(1, "attr", (object)callback); - builder.CloseComponent(); - - // Assert - Assert.Collection( - builder.GetFrames().AsEnumerable(), - frame => AssertFrame.Component(frame, 2, 0), - frame => AssertFrame.Attribute(frame, "attr", callback, 1)); - } - - [Fact] - public void AddAttribute_Element_ObjectEventCallbackOfT_AddsFrame() - { - // Arrange - var builder = new RenderTreeBuilder(); - var callback = new EventCallback(null, new Action((s) => { })); - - // Act - builder.OpenElement(0, "elem"); - builder.AddAttribute(1, "attr", (object)callback); - builder.CloseElement(); - - // Assert - Assert.Collection( - builder.GetFrames().AsEnumerable(), - frame => AssertFrame.Element(frame, "elem", 2, 0), - frame => AssertFrame.Attribute(frame, "attr", callback.Delegate, 1)); - } - - [Fact] - public void AddAttribute_Element_ObjectEventCallbackOfT_Default_DoesNotAddFrame() - { - // Arrange - var builder = new RenderTreeBuilder(); - var callback = default(EventCallback); - - // Act - builder.OpenElement(0, "elem"); - builder.AddAttribute(1, "attr", (object)callback); - builder.CloseElement(); - - // Assert - Assert.Collection( - builder.GetFrames().AsEnumerable(), - frame => AssertFrame.Element(frame, "elem", 1, 0)); - } - - [Fact] - public void AddAttribute_Element_ObjectEventCallbackWithReceiverOfT_AddsFrame() - { - // Arrange - var builder = new RenderTreeBuilder(); - var receiver = Mock.Of(); - var callback = new EventCallback(receiver, new Action((s) => { })); - - // Act - builder.OpenElement(0, "elem"); - builder.AddAttribute(1, "attr", (object)callback); - builder.CloseElement(); - - // Assert - Assert.Collection( - builder.GetFrames().AsEnumerable(), - frame => AssertFrame.Element(frame, "elem", 2, 0), - frame => AssertFrame.Attribute(frame, "attr", new EventCallback(callback.Receiver, callback.Delegate), 1)); - } - - [Fact] - public void AddAttribute_Element_ObjectNull_IgnoresFrame() - { - // Arrange - var builder = new RenderTreeBuilder(); - - // Act - builder.OpenElement(0, "elem"); - builder.AddAttribute(1, "attr", (object)null); - builder.CloseElement(); - - // Assert - Assert.Collection( - builder.GetFrames().AsEnumerable(), - frame => AssertFrame.Element(frame, "elem", 1, 0)); - } - - [Fact] - public void CanAddKeyToElement() - { - // Arrange - var builder = new RenderTreeBuilder(); - var keyValue = new object(); - - // Act - builder.OpenElement(0, "elem"); - builder.AddAttribute(1, "attribute before", "before value"); - builder.SetKey(keyValue); - builder.AddAttribute(2, "attribute after", "after value"); - builder.CloseElement(); - - // Assert - Assert.Collection( - builder.GetFrames().AsEnumerable(), - frame => - { - AssertFrame.Element(frame, "elem", 3, 0); - Assert.Same(keyValue, frame.ElementKey); - }, - frame => AssertFrame.Attribute(frame, "attribute before", "before value", 1), - frame => AssertFrame.Attribute(frame, "attribute after", "after value", 2)); - } - - [Fact] - public void CanAddKeyToComponent() - { - // Arrange - var builder = new RenderTreeBuilder(); - var keyValue = new object(); - - // Act - builder.OpenComponent(0); - builder.AddAttribute(1, "param before", 123); - builder.SetKey(keyValue); - builder.AddAttribute(2, "param after", 456); - builder.CloseComponent(); - - // Assert - Assert.Collection( - builder.GetFrames().AsEnumerable(), - frame => - { - AssertFrame.Component(frame, 3, 0); - Assert.Same(keyValue, frame.ComponentKey); - }, - frame => AssertFrame.Attribute(frame, "param before", 123, 1), - frame => AssertFrame.Attribute(frame, "param after", 456, 2)); - } - - [Fact] - public void CannotAddKeyOutsideComponentOrElement_TreeRoot() - { - // Arrange - var builder = new RenderTreeBuilder(); - - // Act/Assert - var ex = Assert.Throws(() => - { - builder.SetKey(new object()); - }); - Assert.Equal("Cannot set a key outside the scope of a component or element.", ex.Message); - } - - [Fact] - public void CannotAddKeyOutsideComponentOrElement_RegionRoot() - { - // Arrange - var builder = new RenderTreeBuilder(); - - // Act/Assert - builder.OpenElement(0, "some element"); - builder.OpenRegion(1); - var ex = Assert.Throws(() => - { - builder.SetKey(new object()); - }); - Assert.Equal($"Cannot set a key on a frame of type {RenderTreeFrameType.Region}.", ex.Message); - } - - [Fact] - public void IgnoresNullElementKey() - { - // Arrange - var builder = new RenderTreeBuilder(); - - // Act - builder.OpenElement(0, "elem"); - builder.SetKey(null); - builder.CloseElement(); - - // Assert - Assert.Collection( - builder.GetFrames().AsEnumerable(), - frame => - { - AssertFrame.Element(frame, "elem", 1, 0); - Assert.Null(frame.ElementKey); - }); - } - - [Fact] - public void IgnoresNullComponentKey() - { - // Arrange - var builder = new RenderTreeBuilder(); - - // Act - builder.OpenComponent(0); - builder.SetKey(null); - builder.CloseComponent(); - - // Assert - Assert.Collection( - builder.GetFrames().AsEnumerable(), - frame => - { - AssertFrame.Component(frame, 1, 0); - Assert.Null(frame.ComponentKey); - }); - } - - [Fact] - public void ProcessDuplicateAttributes_DoesNotRemoveDuplicatesWithoutAddMultipleAttributes() - { - // Arrange - var builder = new RenderTreeBuilder(); - builder.OpenElement(0, "div"); - builder.AddAttribute(0, "id", "hi"); - builder.AddAttribute(0, "id", "bye"); - builder.CloseElement(); - - // Act - var frames = builder.GetFrames().AsEnumerable(); - - // Assert - Assert.Collection( - frames, - f => AssertFrame.Element(f, "div", 3, 0), - f => AssertFrame.Attribute(f, "id", "hi"), - f => AssertFrame.Attribute(f, "id", "bye")); - } - - - [Fact] - public void ProcessDuplicateAttributes_StopsAtFirstNonAttributeFrame_Capture() - { - // Arrange - var capture = (Action)((_) => { }); - - var builder = new RenderTreeBuilder(); - builder.OpenElement(0, "div"); - builder.AddAttribute(0, "id", "hi"); - builder.AddMultipleAttributes(0, new Dictionary(StringComparer.OrdinalIgnoreCase) - { - { "id", "bye" }, - }); - builder.AddElementReferenceCapture(0, capture); - builder.CloseElement(); - - // Act - var frames = builder.GetFrames().AsEnumerable(); - - // Assert - Assert.Collection( - frames, - f => AssertFrame.Element(f, "div", 3, 0), - f => AssertFrame.Attribute(f, "id", "bye"), - f => AssertFrame.ElementReferenceCapture(f, capture)); - } - - [Fact] - public void ProcessDuplicateAttributes_StopsAtFirstNonAttributeFrame_Content() - { - // Arrange - var builder = new RenderTreeBuilder(); - builder.OpenElement(0, "div"); - builder.AddAttribute(0, "id", "hi"); - builder.AddMultipleAttributes(0, new Dictionary(StringComparer.OrdinalIgnoreCase) - { - { "id", "bye" }, - }); - builder.AddContent(0, "hey"); - builder.CloseElement(); - - // Act - var frames = builder.GetFrames().AsEnumerable(); - - // Assert - Assert.Collection( - frames, - f => AssertFrame.Element(f, "div", 3, 0), - f => AssertFrame.Attribute(f, "id", "bye"), - f => AssertFrame.Text(f, "hey")); - } - - [Fact] - public void ProcessDuplicateAttributes_CanRemoveDuplicateInsideElement() - { - // Arrange - var builder = new RenderTreeBuilder(); - builder.OpenElement(0, "div"); - builder.AddAttribute(0, "id", "hi"); - builder.AddMultipleAttributes(0, new Dictionary(StringComparer.OrdinalIgnoreCase) - { - { "id", "bye" }, - }); - builder.CloseElement(); - - // Act - var frames = builder.GetFrames().AsEnumerable(); - - // Assert - Assert.Collection( - frames, - f => AssertFrame.Element(f, "div", 2, 0), - f => AssertFrame.Attribute(f, "id", "bye")); - } - - [Fact] - public void ProcessDuplicateAttributes_CanRemoveDuplicateInsideComponent() - { - // Arrange - var builder = new RenderTreeBuilder(); - builder.OpenComponent(0); - builder.AddAttribute(0, "id", "hi"); - builder.AddMultipleAttributes(0, new Dictionary(StringComparer.OrdinalIgnoreCase) - { - { "id", "bye" }, - }); - builder.CloseComponent(); - - // Act - var frames = builder.GetFrames().AsEnumerable(); - - // Assert - Assert.Collection( - frames, - f => AssertFrame.Component(f, 2, 0), - f => AssertFrame.Attribute(f, "id", "bye")); - } - - // This covers a special case we have to handle explicitly in the RTB logic. - [Fact] - public void ProcessDuplicateAttributes_SilentFrameFollowedBySameAttribute() - { - // Arrange - var builder = new RenderTreeBuilder(); - builder.OpenComponent(0); - builder.AddAttribute(0, "id", (string)null); - builder.AddMultipleAttributes(0, new Dictionary(StringComparer.OrdinalIgnoreCase) - { - { "id", "bye" }, - }); - builder.CloseComponent(); - - // Act - var frames = builder.GetFrames().AsEnumerable(); - - // Assert - Assert.Collection( - frames, - f => AssertFrame.Component(f, 2, 0), - f => AssertFrame.Attribute(f, "id", "bye")); - } - - [Fact] - public void ProcessDuplicateAttributes_DoesNotRemoveDuplicatesInsideChildElement() - { - // Arrange - var builder = new RenderTreeBuilder(); - builder.OpenElement(0, "div"); - builder.AddAttribute(0, "id", "hi"); - builder.AddMultipleAttributes(0, new Dictionary(StringComparer.OrdinalIgnoreCase) - { - { "id", "bye" }, - }); - builder.OpenElement(0, "strong"); - builder.AddAttribute(0, "id", "hi"); - builder.AddAttribute(0, "id", "bye"); - builder.CloseElement(); - builder.CloseElement(); - - // Act - var frames = builder.GetFrames().AsEnumerable(); - - // Assert - Assert.Collection( - frames, - f => AssertFrame.Element(f, "div", 5, 0), - f => AssertFrame.Attribute(f, "id", "bye"), - f => AssertFrame.Element(f, "strong", 3), - f => AssertFrame.Attribute(f, "id", "hi"), - f => AssertFrame.Attribute(f, "id", "bye")); - } - - [Fact] - public void ProcessDuplicateAttributes_CanRemoveOverwrittenAttributes() - { - // Arrange - var builder = new RenderTreeBuilder(); - builder.OpenElement(0, "div"); - builder.AddAttribute(0, "A", "hi"); - builder.AddAttribute(0, "2", new EventCallback(null, (Action)(() => { }))); - builder.AddMultipleAttributes(0, new Dictionary(StringComparer.OrdinalIgnoreCase) - { - { "a", null }, // Replace with null value (case-insensitive) - { "2", false }, // Replace with 'false' - { "3", "hey there" }, // Add a new value - }); - builder.AddAttribute(0, "3", "see ya"); // Overwrite value added by splat - builder.AddAttribute(0, "4", false); // Add a false value - builder.AddAttribute(0, "5", "another one"); - builder.AddMultipleAttributes(0, new Dictionary(StringComparer.OrdinalIgnoreCase) - { - { "5", null }, // overwrite value with null - { "6", new EventCallback(null, (Action)(() =>{ })) }, - }); - builder.AddAttribute(0, "6", default(EventCallback)); // Replace with a 'silent' EventCallback - builder.CloseElement(); - - // Act - var frames = builder.GetFrames().AsEnumerable(); - - // Assert - Assert.Collection( - frames, - f => AssertFrame.Element(f, "div", 2, 0), - f => AssertFrame.Attribute(f, "3", "see ya")); - } - - private class TestComponent : IComponent - { - public void Attach(RenderHandle renderHandle) { } - - public Task SetParametersAsync(ParameterView parameters) - => throw new NotImplementedException(); - } - - private class TestRenderer : Renderer - { - public TestRenderer() : base(new TestServiceProvider(), NullLoggerFactory.Instance) - { - } - - public override Dispatcher Dispatcher { get; } = Dispatcher.CreateDefault(); - - protected override void HandleException(Exception exception) - => throw new NotImplementedException(); - - protected override Task UpdateDisplayAsync(in RenderBatch renderBatch) - => throw new NotImplementedException(); - } - } -} diff --git a/src/Components/Components/test/Rendering/RendererSynchronizationContextTest.cs b/src/Components/Components/test/Rendering/RendererSynchronizationContextTest.cs deleted file mode 100644 index 568d2501bb..0000000000 --- a/src/Components/Components/test/Rendering/RendererSynchronizationContextTest.cs +++ /dev/null @@ -1,767 +0,0 @@ -// 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.Diagnostics; -using System.Globalization; -using System.Threading; -using System.Threading.Tasks; -using Xunit; - -namespace Microsoft.AspNetCore.Components.Rendering -{ - public class RendererSynchronizationContextTest - { - // Nothing should exceed the timeout in a successful run of the the tests, this is just here to catch - // failures. - public TimeSpan Timeout = Debugger.IsAttached ? System.Threading.Timeout.InfiniteTimeSpan : TimeSpan.FromSeconds(10); - - [Fact] - public void Post_RunsAsynchronously_WhenNotBusy() - { - // Arrange - var context = new RendererSynchronizationContext(); - var thread = Thread.CurrentThread; - Thread capturedThread = null; - - var e = new ManualResetEventSlim(); - - // Act - context.Post((_) => - { - capturedThread = Thread.CurrentThread; - - e.Set(); - }, null); - - // Assert - Assert.True(e.Wait(Timeout), "timeout"); - Assert.NotSame(thread, capturedThread); - } - - [Fact] - public void Post_RunsAynchronously_WhenNotBusy_Exception() - { - // Arrange - var context = new RendererSynchronizationContext(); - - Exception exception = null; - context.UnhandledException += (sender, e) => - { - exception = (InvalidTimeZoneException)e.ExceptionObject; - }; - - // Act - context.Post((_) => - { - throw new InvalidTimeZoneException(); - }, null); - - // Assert - // - // Use another item to 'push through' the throwing one - context.Send((_) => { }, null); - Assert.NotNull(exception); - } - - [Fact] - public async Task Post_CanRunAsynchronously_WhenBusy() - { - // Arrange - var context = new RendererSynchronizationContext(); - var thread = Thread.CurrentThread; - Thread capturedThread = null; - - var e1 = new ManualResetEventSlim(); - var e2 = new ManualResetEventSlim(); - var e3 = new ManualResetEventSlim(); - - var task = Task.Run(() => - { - context.Send((_) => - { - e1.Set(); - Assert.True(e2.Wait(Timeout), "timeout"); - }, null); - }); - - Assert.True(e1.Wait(Timeout), "timeout"); - - // Act - context.Post((_) => - { - capturedThread = Thread.CurrentThread; - - e3.Set(); - }, null); - - // Assert - Assert.False(e2.IsSet); - e2.Set(); // Unblock the first item - await task; - - Assert.True(e3.Wait(Timeout), "timeout"); - Assert.NotSame(thread, capturedThread); - } - - [Fact] - public async Task Post_CanRunAsynchronously_CaptureExecutionContext() - { - // Arrange - var context = new RendererSynchronizationContext(); - - // CultureInfo uses the execution context. - CultureInfo.CurrentCulture = new CultureInfo("en-GB"); - CultureInfo capturedCulture = null; - - SynchronizationContext capturedContext = null; - - var e1 = new ManualResetEventSlim(); - var e2 = new ManualResetEventSlim(); - var e3 = new ManualResetEventSlim(); - - var task = Task.Run(() => - { - context.Send((_) => - { - e1.Set(); - Assert.True(e2.Wait(Timeout), "timeout"); - }, null); - }); - - Assert.True(e1.Wait(Timeout), "timeout"); - - // Act - SynchronizationContext original = SynchronizationContext.Current; - - try - { - SynchronizationContext.SetSynchronizationContext(context); - context.Post((_) => - { - capturedCulture = CultureInfo.CurrentCulture; - capturedContext = SynchronizationContext.Current; - e3.Set(); - }, null); - } - finally - { - SynchronizationContext.SetSynchronizationContext(original); - } - - // Assert - Assert.False(e2.IsSet); - e2.Set(); // Unblock the first item - await task; - - Assert.True(e3.Wait(Timeout), "timeout"); - Assert.Same(CultureInfo.CurrentCulture, capturedCulture); - Assert.Same(context, capturedContext); - } - - [Fact] - public async Task Post_CanRunAsynchronously_WhenBusy_Exception() - { - // Arrange - var context = new RendererSynchronizationContext(); - - Exception exception = null; - context.UnhandledException += (sender, e) => - { - exception = (InvalidTimeZoneException)e.ExceptionObject; - }; - - var e1 = new ManualResetEventSlim(); - var e2 = new ManualResetEventSlim(); - - var task = Task.Run(() => - { - context.Send((_) => - { - e1.Set(); - Assert.True(e2.Wait(Timeout), "timeout"); - }, null); - }); - - Assert.True(e1.Wait(Timeout), "timeout"); - - // Act - context.Post((_) => - { - throw new InvalidTimeZoneException(); - }, null); - - // Assert - Assert.False(e2.IsSet); - e2.Set(); // Unblock the first item - await task; - - // Use another item to 'push through' the throwing one - context.Send((_) => { }, null); - Assert.NotNull(exception); - } - - [Fact] - public async Task Post_BackgroundWorkItem_CanProcessMoreItemsInline() - { - // Arrange - var context = new RendererSynchronizationContext(); - Thread capturedThread = null; - - var e1 = new ManualResetEventSlim(); - var e2 = new ManualResetEventSlim(); - var e3 = new ManualResetEventSlim(); - var e4 = new ManualResetEventSlim(); - var e5 = new ManualResetEventSlim(); - var e6 = new ManualResetEventSlim(); - - // Force task2 to execute in the background - var task1 = Task.Run(() => context.Send((_) => - { - e1.Set(); - Assert.True(e2.Wait(Timeout), "timeout"); - }, null)); - - Assert.True(e1.Wait(Timeout), "timeout"); - - var task2 = Task.Run(() => - { - context.Send((_) => - { - e3.Set(); - Assert.True(e4.Wait(Timeout), "timeout"); - capturedThread = Thread.CurrentThread; - }, null); - }); - - e2.Set(); - await task1; - - Assert.True(e3.Wait(Timeout), "timeout"); - - // Act - // - // Now task2 is 'running' in the sync context. Schedule more work items - they will be - // run immediately after the second item - context.Post((_) => - { - e5.Set(); - Assert.Same(Thread.CurrentThread, capturedThread); - }, null); - context.Post((_) => - { - e6.Set(); - Assert.Same(Thread.CurrentThread, capturedThread); - }, null); - - - // Assert - e4.Set(); - await task2; - - Assert.True(e5.Wait(Timeout), "timeout"); - Assert.True(e6.Wait(Timeout), "timeout"); - } - - [Fact] - public void Post_CapturesContext() - { - // Arrange - var context = new RendererSynchronizationContext(); - - var e1 = new ManualResetEventSlim(); - - // CultureInfo uses the execution context. - CultureInfo.CurrentCulture = new CultureInfo("en-GB"); - CultureInfo capturedCulture = null; - - SynchronizationContext capturedContext = null; - - // Act - context.Post(async (_) => - { - await Task.Yield(); - - capturedCulture = CultureInfo.CurrentCulture; - capturedContext = SynchronizationContext.Current; - e1.Set(); - }, null); - - // Assert - Assert.True(e1.Wait(Timeout), "timeout"); - Assert.Same(CultureInfo.CurrentCulture, capturedCulture); - Assert.Same(context, capturedContext); - } - - [Fact] - public void Send_CanRunSynchronously() - { - // Arrange - var context = new RendererSynchronizationContext(); - var thread = Thread.CurrentThread; - Thread capturedThread = null; - - // Act - context.Send((_) => - { - capturedThread = Thread.CurrentThread; - }, null); - - // Assert - Assert.Same(thread, capturedThread); - } - - [Fact] - public void Send_CanRunSynchronously_Exception() - { - // Arrange - var context = new RendererSynchronizationContext(); - - // Act & Assert - Assert.Throws(() => context.Send((_) => - { - throw new InvalidTimeZoneException(); - }, null)); - } - - [Fact] - public async Task Send_BlocksWhenOtherWorkRunning() - { - // Arrange - var context = new RendererSynchronizationContext(); - - var e1 = new ManualResetEventSlim(); - var e2 = new ManualResetEventSlim(); - var e3 = new ManualResetEventSlim(); - var e4 = new ManualResetEventSlim(); - - // Force task2 to execute in the background - var task1 = Task.Run(() => - { - context.Send((_) => - { - e1.Set(); - Assert.True(e2.Wait(Timeout), "timeout"); - }, null); - }); - - Assert.True(e1.Wait(Timeout), "timeout"); - - // Act - // - // Dispatch this on the background thread because otherwise it would block. - var task2 = Task.Run(() => - { - e3.Set(); - context.Send((_) => - { - e4.Set(); - }, null); - }); - - // Assert - Assert.True(e3.Wait(Timeout), "timeout"); - Assert.True(e3.IsSet); - - // Unblock the first item - e2.Set(); - await task1; - - await task2; - Assert.True(e4.IsSet); - } - - [Fact] - public void Send_CapturesContext() - { - // Arrange - var context = new RendererSynchronizationContext(); - - var e1 = new ManualResetEventSlim(); - - // CultureInfo uses the execution context. - CultureInfo.CurrentCulture = new CultureInfo("en-GB"); - CultureInfo capturedCulture = null; - - SynchronizationContext capturedContext = null; - - // Act - context.Send(async (_) => - { - await Task.Yield(); - - capturedCulture = CultureInfo.CurrentCulture; - capturedContext = SynchronizationContext.Current; - - e1.Set(); - }, null); - - // Assert - Assert.True(e1.Wait(Timeout), "timeout"); - Assert.Same(CultureInfo.CurrentCulture, capturedCulture); - Assert.Same(context, capturedContext); - } - - [Fact] - public async Task InvokeAsync_Action_CanRunSynchronously_WhenNotBusy() - { - // Arrange - var context = new RendererSynchronizationContext(); - var thread = Thread.CurrentThread; - Thread capturedThread = null; - - // Act - var task = context.InvokeAsync(() => - { - capturedThread = Thread.CurrentThread; - }); - - // Assert - await task; - Assert.Same(thread, capturedThread); - } - - [Fact] - public async Task InvokeAsync_Action_CanRunAsynchronously_WhenBusy() - { - // Arrange - var context = new RendererSynchronizationContext(); - var thread = Thread.CurrentThread; - Thread capturedThread = null; - - var e1 = new ManualResetEventSlim(); - var e2 = new ManualResetEventSlim(); - var e3 = new ManualResetEventSlim(); - - var task1 = Task.Run(() => - { - context.Send((_) => - { - e1.Set(); - Assert.True(e2.Wait(Timeout), "timeout"); - }, null); - }); - - Assert.True(e1.Wait(Timeout), "timeout"); - - var task2 = context.InvokeAsync(() => - { - capturedThread = Thread.CurrentThread; - - e3.Set(); - }); - - // Assert - Assert.False(e2.IsSet); - e2.Set(); // Unblock the first item - await task1; - - Assert.True(e3.Wait(Timeout), "timeout"); - await task2; - Assert.NotSame(thread, capturedThread); - } - - [Fact] - public async Task InvokeAsync_Action_CanRethrowExceptions() - { - // Arrange - var context = new RendererSynchronizationContext(); - - // Act - var task = context.InvokeAsync((Action)(() => - { - throw new InvalidTimeZoneException(); - })); - - // Assert - await Assert.ThrowsAsync(async () => await task); - } - - [Fact] - public async Task InvokeAsync_Action_CanReportCancellation() - { - // Arrange - var context = new RendererSynchronizationContext(); - - // Act - var task = context.InvokeAsync((Action)(() => - { - throw new OperationCanceledException(); - })); - - // Assert - Assert.Equal(TaskStatus.Canceled, task.Status); - await Assert.ThrowsAsync(async () => await task); - } - - [Fact] - public async Task InvokeAsync_FuncT_CanRunSynchronously_WhenNotBusy() - { - // Arrange - var context = new RendererSynchronizationContext(); - var thread = Thread.CurrentThread; - - // Act - var task = context.InvokeAsync(() => - { - return Thread.CurrentThread; - }); - - // Assert - Assert.Same(thread, await task); - } - - [Fact] - public async Task InvokeAsync_FuncT_CanRunAsynchronously_WhenBusy() - { - // Arrange - var context = new RendererSynchronizationContext(); - var thread = Thread.CurrentThread; - - var e1 = new ManualResetEventSlim(); - var e2 = new ManualResetEventSlim(); - var e3 = new ManualResetEventSlim(); - - var task1 = Task.Run(() => - { - context.Send((_) => - { - e1.Set(); - Assert.True(e2.Wait(Timeout), "timeout"); - }, null); - }); - - Assert.True(e1.Wait(Timeout), "timeout"); - - var task2 = context.InvokeAsync(() => - { - e3.Set(); - - return Thread.CurrentThread; - }); - - // Assert - Assert.False(e2.IsSet); - e2.Set(); // Unblock the first item - await task1; - - Assert.True(e3.Wait(Timeout), "timeout"); - Assert.NotSame(thread, await task2); - } - - [Fact] - public async Task InvokeAsync_FuncT_CanRethrowExceptions() - { - // Arrange - var context = new RendererSynchronizationContext(); - - // Act - var task = context.InvokeAsync((Func)(() => - { - throw new InvalidTimeZoneException(); - })); - - // Assert - await Assert.ThrowsAsync(async () => await task); - } - - [Fact] - public async Task InvokeAsync_FuncT_CanReportCancellation() - { - // Arrange - var context = new RendererSynchronizationContext(); - - // Act - var task = context.InvokeAsync((Func)(() => - { - throw new OperationCanceledException(); - })); - - // Assert - Assert.Equal(TaskStatus.Canceled, task.Status); - await Assert.ThrowsAsync(async () => await task); - } - - [Fact] - public async Task InvokeAsync_FuncTask_CanRunSynchronously_WhenNotBusy() - { - // Arrange - var context = new RendererSynchronizationContext(); - var thread = Thread.CurrentThread; - Thread capturedThread = null; - - // Act - var task = context.InvokeAsync(() => - { - capturedThread = Thread.CurrentThread; - return Task.CompletedTask; - }); - - // Assert - await task; - Assert.Same(thread, capturedThread); - } - - [Fact] - public async Task InvokeAsync_FuncTask_CanRunAsynchronously_WhenBusy() - { - // Arrange - var context = new RendererSynchronizationContext(); - var thread = Thread.CurrentThread; - Thread capturedThread = null; - - var e1 = new ManualResetEventSlim(); - var e2 = new ManualResetEventSlim(); - var e3 = new ManualResetEventSlim(); - - var task1 = Task.Run(() => - { - context.Send((_) => - { - e1.Set(); - Assert.True(e2.Wait(Timeout), "timeout"); - }, null); - }); - - Assert.True(e1.Wait(Timeout), "timeout"); - - var task2 = context.InvokeAsync(() => - { - capturedThread = Thread.CurrentThread; - - e3.Set(); - return Task.CompletedTask; - }); - - // Assert - Assert.False(e2.IsSet); - e2.Set(); // Unblock the first item - await task1; - - Assert.True(e3.Wait(Timeout), "timeout"); - await task2; - Assert.NotSame(thread, capturedThread); - } - - [Fact] - public async Task InvokeAsync_FuncTask_CanRethrowExceptions() - { - // Arrange - var context = new RendererSynchronizationContext(); - - // Act - var task = context.InvokeAsync(() => - { - throw new InvalidTimeZoneException(); - }); - - // Assert - await Assert.ThrowsAsync(async () => await task); - } - - [Fact] - public async Task InvokeAsync_FuncTask_CanReportCancellation() - { - // Arrange - var context = new RendererSynchronizationContext(); - - // Act - var task = context.InvokeAsync(() => - { - throw new OperationCanceledException(); - }); - - // Assert - Assert.Equal(TaskStatus.Canceled, task.Status); - await Assert.ThrowsAsync(async () => await task); - } - - [Fact] - public async Task InvokeAsync_FuncTaskT_CanRunSynchronously_WhenNotBusy() - { - // Arrange - var context = new RendererSynchronizationContext(); - var thread = Thread.CurrentThread; - - // Act - var task = context.InvokeAsync(() => - { - return Task.FromResult(Thread.CurrentThread); - }); - - // Assert - Assert.Same(thread, await task); - } - - [Fact] - public async Task InvokeAsync_FuncTaskT_CanRunAsynchronously_WhenBusy() - { - // Arrange - var context = new RendererSynchronizationContext(); - var thread = Thread.CurrentThread; - - var e1 = new ManualResetEventSlim(); - var e2 = new ManualResetEventSlim(); - var e3 = new ManualResetEventSlim(); - - var task1 = Task.Run(() => - { - context.Send((_) => - { - e1.Set(); - Assert.True(e2.Wait(Timeout), "timeout"); - }, null); - }); - - Assert.True(e1.Wait(Timeout), "timeout"); - - var task2 = context.InvokeAsync(() => - { - e3.Set(); - - return Task.FromResult(Thread.CurrentThread); - }); - - // Assert - Assert.False(e2.IsSet); - e2.Set(); // Unblock the first item - await task1; - - Assert.True(e3.Wait(Timeout), "timeout"); - Assert.NotSame(thread, await task2); - } - - [Fact] - public async Task InvokeAsync_FuncTaskT_CanRethrowExceptions() - { - // Arrange - var context = new RendererSynchronizationContext(); - - // Act - var task = context.InvokeAsync((Func>)(() => - { - throw new InvalidTimeZoneException(); - })); - - // Assert - await Assert.ThrowsAsync(async () => await task); - } - - [Fact] - public async Task InvokeAsync_FuncTaskT_CanReportCancellation() - { - // Arrange - var context = new RendererSynchronizationContext(); - - // Act - var task = context.InvokeAsync((Func>)(() => - { - throw new OperationCanceledException(); - })); - - // Assert - Assert.Equal(TaskStatus.Canceled, task.Status); - await Assert.ThrowsAsync(async () => await task); - } - } -} diff --git a/src/Components/Components/test/Rendering/TestArrayPool.cs b/src/Components/Components/test/Rendering/TestArrayPool.cs deleted file mode 100644 index c5335a6b64..0000000000 --- a/src/Components/Components/test/Rendering/TestArrayPool.cs +++ /dev/null @@ -1,23 +0,0 @@ -// 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.Buffers; -using System.Collections.Generic; - -namespace Microsoft.AspNetCore.Components.RenderTree -{ - internal class TestArrayPool : ArrayPool - { - public override T[] Rent(int minimumLength) - { - return new T[minimumLength]; - } - - public List ReturnedBuffers = new List(); - - public override void Return(T[] array, bool clearArray = false) - { - ReturnedBuffers.Add(array); - } - } -} diff --git a/src/Components/Components/test/RouteViewTest.cs b/src/Components/Components/test/RouteViewTest.cs deleted file mode 100644 index 05b1c8b20f..0000000000 --- a/src/Components/Components/test/RouteViewTest.cs +++ /dev/null @@ -1,209 +0,0 @@ -// 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.Collections.Generic; -using System.Linq; -using Microsoft.AspNetCore.Components.Rendering; -using Microsoft.AspNetCore.Components.RenderTree; -using Microsoft.AspNetCore.Components.Test.Helpers; -using Xunit; - -namespace Microsoft.AspNetCore.Components.Test -{ - public class RouteViewTest - { - private readonly TestRenderer _renderer; - private readonly RouteView _routeViewComponent; - private readonly int _routeViewComponentId; - - public RouteViewTest() - { - _renderer = new TestRenderer(); - _routeViewComponent = new RouteView(); - _routeViewComponentId = _renderer.AssignRootComponentId(_routeViewComponent); - } - - [Fact] - public void ThrowsIfNoRouteDataSupplied() - { - var ex = Assert.Throws(() => - { - // Throws synchronously, so no need to await - _ = _routeViewComponent.SetParametersAsync(ParameterView.Empty); - }); - - - Assert.Equal($"The {nameof(RouteView)} component requires a non-null value for the parameter {nameof(RouteView.RouteData)}.", ex.Message); - } - - [Fact] - public void RendersPageInsideLayoutView() - { - // Arrange - var routeParams = new Dictionary - { - { nameof(ComponentWithLayout.Message), "Test message" } - }; - var routeData = new RouteData(typeof(ComponentWithLayout), routeParams); - - // Act - _renderer.Dispatcher.InvokeAsync(() => _routeViewComponent.SetParametersAsync(ParameterView.FromDictionary(new Dictionary - { - { nameof(RouteView.RouteData), routeData }, - }))); - - // Assert: RouteView renders LayoutView - var batch = _renderer.Batches.Single(); - var routeViewFrames = _renderer.GetCurrentRenderTreeFrames(_routeViewComponentId).AsEnumerable(); - Assert.Collection(routeViewFrames, - frame => AssertFrame.Component(frame, subtreeLength: 3, sequence: 0), - frame => AssertFrame.Attribute(frame, nameof(LayoutView.Layout), (object)typeof(TestLayout), sequence: 1), - frame => AssertFrame.Attribute(frame, nameof(LayoutView.ChildContent), sequence: 2)); - - // Assert: LayoutView renders TestLayout - var layoutViewComponentId = batch.GetComponentFrames().Single().ComponentId; - var layoutViewFrames = _renderer.GetCurrentRenderTreeFrames(layoutViewComponentId).AsEnumerable(); - Assert.Collection(layoutViewFrames, - frame => AssertFrame.Component(frame, subtreeLength: 2, sequence: 0), - frame => AssertFrame.Attribute(frame, nameof(LayoutComponentBase.Body), sequence: 1)); - - // Assert: TestLayout renders page - var testLayoutComponentId = batch.GetComponentFrames().Single().ComponentId; - var testLayoutFrames = _renderer.GetCurrentRenderTreeFrames(testLayoutComponentId).AsEnumerable(); - Assert.Collection(testLayoutFrames, - frame => AssertFrame.Text(frame, "Layout starts here", sequence: 0), - frame => AssertFrame.Region(frame, subtreeLength: 3), - frame => AssertFrame.Component(frame, sequence: 0, subtreeLength: 2), - frame => AssertFrame.Attribute(frame, nameof(ComponentWithLayout.Message), "Test message", sequence: 1), - frame => AssertFrame.Text(frame, "Layout ends here", sequence: 2)); - - // Assert: page itself is rendered, having received parameters from the original route data - var pageComponentId = batch.GetComponentFrames().Single().ComponentId; - var pageFrames = _renderer.GetCurrentRenderTreeFrames(pageComponentId).AsEnumerable(); - Assert.Collection(pageFrames, - frame => AssertFrame.Text(frame, "Hello from the page with message 'Test message'", sequence: 0)); - - // Assert: nothing else was rendered - Assert.Equal(4, batch.DiffsInOrder.Count); - } - - [Fact] - public void UsesDefaultLayoutIfNoneSetOnPage() - { - // Arrange - var routeParams = new Dictionary(); - var routeData = new RouteData(typeof(ComponentWithoutLayout), routeParams); - - // Act - _renderer.Dispatcher.InvokeAsync(() => _routeViewComponent.SetParametersAsync(ParameterView.FromDictionary(new Dictionary - { - { nameof(RouteView.RouteData), routeData }, - { nameof(RouteView.DefaultLayout), typeof(OtherLayout) }, - }))); - - // Assert: uses default layout - // Not asserting about what else gets rendered as that's covered by other tests - var batch = _renderer.Batches.Single(); - var routeViewFrames = _renderer.GetCurrentRenderTreeFrames(_routeViewComponentId).AsEnumerable(); - Assert.Collection(routeViewFrames, - frame => AssertFrame.Component(frame, subtreeLength: 3, sequence: 0), - frame => AssertFrame.Attribute(frame, nameof(LayoutView.Layout), (object)typeof(OtherLayout), sequence: 1), - frame => AssertFrame.Attribute(frame, nameof(LayoutView.ChildContent), sequence: 2)); - } - - [Fact] - public void UsesNoLayoutIfNoneSetOnPageAndNoDefaultSet() - { - // Arrange - var routeParams = new Dictionary(); - var routeData = new RouteData(typeof(ComponentWithoutLayout), routeParams); - - // Act - _renderer.Dispatcher.InvokeAsync(() => _routeViewComponent.SetParametersAsync(ParameterView.FromDictionary(new Dictionary - { - { nameof(RouteView.RouteData), routeData }, - }))); - - // Assert: uses no layout - // Not asserting about what else gets rendered as that's covered by other tests - var batch = _renderer.Batches.Single(); - var routeViewFrames = _renderer.GetCurrentRenderTreeFrames(_routeViewComponentId).AsEnumerable(); - Assert.Collection(routeViewFrames, - frame => AssertFrame.Component(frame, subtreeLength: 3, sequence: 0), - frame => AssertFrame.Attribute(frame, nameof(LayoutView.Layout), (object)null, sequence: 1), - frame => AssertFrame.Attribute(frame, nameof(LayoutView.ChildContent), sequence: 2)); - } - - [Fact] - public void PageLayoutSupersedesDefaultLayout() - { - // Arrange - var routeParams = new Dictionary(); - var routeData = new RouteData(typeof(ComponentWithLayout), routeParams); - - // Act - _renderer.Dispatcher.InvokeAsync(() => _routeViewComponent.SetParametersAsync(ParameterView.FromDictionary(new Dictionary - { - { nameof(RouteView.RouteData), routeData }, - { nameof(RouteView.DefaultLayout), typeof(OtherLayout) }, - }))); - - // Assert: uses layout specified by page - // Not asserting about what else gets rendered as that's covered by other tests - var batch = _renderer.Batches.Single(); - var routeViewFrames = _renderer.GetCurrentRenderTreeFrames(_routeViewComponentId).AsEnumerable(); - Assert.Collection(routeViewFrames, - frame => AssertFrame.Component(frame, subtreeLength: 3, sequence: 0), - frame => AssertFrame.Attribute(frame, nameof(LayoutView.Layout), (object)typeof(TestLayout), sequence: 1), - frame => AssertFrame.Attribute(frame, nameof(LayoutView.ChildContent), sequence: 2)); - } - - private class ComponentWithoutLayout : AutoRenderComponent - { - [Parameter] public string Message { get; set; } - - protected override void BuildRenderTree(RenderTreeBuilder builder) - { - builder.AddContent(0, $"Hello from the page with message '{Message}'"); - } - } - - [Layout(typeof(TestLayout))] - private class ComponentWithLayout : AutoRenderComponent - { - [Parameter] public string Message { get; set; } - - protected override void BuildRenderTree(RenderTreeBuilder builder) - { - builder.AddContent(0, $"Hello from the page with message '{Message}'"); - } - } - - private class TestLayout : AutoRenderComponent - { - [Parameter] - public RenderFragment Body { get; set; } - - protected override void BuildRenderTree(RenderTreeBuilder builder) - { - builder.AddContent(0, "Layout starts here"); - builder.AddContent(1, Body); - builder.AddContent(2, "Layout ends here"); - } - } - - private class OtherLayout : AutoRenderComponent - { - [Parameter] - public RenderFragment Body { get; set; } - - protected override void BuildRenderTree(RenderTreeBuilder builder) - { - builder.AddContent(0, "OtherLayout starts here"); - builder.AddContent(1, Body); - builder.AddContent(2, "OtherLayout ends here"); - } - } - } -} diff --git a/src/Components/Components/test/Routing/RouteConstraintTest.cs b/src/Components/Components/test/Routing/RouteConstraintTest.cs deleted file mode 100644 index 34889f03dd..0000000000 --- a/src/Components/Components/test/Routing/RouteConstraintTest.cs +++ /dev/null @@ -1,36 +0,0 @@ -// 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 Xunit; - -namespace Microsoft.AspNetCore.Components.Routing -{ - public class RouteConstraintTest - { - [Fact] - public void Parse_CreatesDifferentConstraints_ForDifferentKinds() - { - // Arrange - var original = RouteConstraint.Parse("ignore", "ignore", "int"); - - // Act - var another = RouteConstraint.Parse("ignore", "ignore", "guid"); - - // Assert - Assert.NotSame(original, another); - } - - [Fact] - public void Parse_CachesCreatedConstraint_ForSameKind() - { - // Arrange - var original = RouteConstraint.Parse("ignore", "ignore", "int"); - - // Act - var another = RouteConstraint.Parse("ignore", "ignore", "int"); - - // Assert - Assert.Same(original, another); - } - } -} diff --git a/src/Components/Components/test/Routing/RouteTableFactoryTests.cs b/src/Components/Components/test/Routing/RouteTableFactoryTests.cs deleted file mode 100644 index 92bea90d79..0000000000 --- a/src/Components/Components/test/Routing/RouteTableFactoryTests.cs +++ /dev/null @@ -1,504 +0,0 @@ -// 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.Collections.Generic; -using System.Linq; -using Microsoft.AspNetCore.Components.Routing; -using Xunit; - -namespace Microsoft.AspNetCore.Components.Test.Routing -{ - public class RouteTableFactoryTests - { - [Fact] - public void CanCacheRouteTable() - { - // Arrange - var routes1 = RouteTableFactory.Create(new[] { GetType().Assembly, }); - - // Act - var routes2 = RouteTableFactory.Create(new[] { GetType().Assembly, }); - - // Assert - Assert.Same(routes1, routes2); - } - - [Fact] - public void CanCacheRouteTableWithDifferentAssembliesAndOrder() - { - // Arrange - var routes1 = RouteTableFactory.Create(new[] { typeof(object).Assembly, GetType().Assembly, }); - - // Act - var routes2 = RouteTableFactory.Create(new[] { GetType().Assembly, typeof(object).Assembly, }); - - // Assert - Assert.Same(routes1, routes2); - } - - [Fact] - public void DoesNotCacheRouteTableForDifferentAssemblies() - { - // Arrange - var routes1 = RouteTableFactory.Create(new[] { GetType().Assembly, }); - - // Act - var routes2 = RouteTableFactory.Create(new[] { GetType().Assembly, typeof(object).Assembly, }); - - // Assert - Assert.NotSame(routes1, routes2); - } - - [Fact] - public void CanDiscoverRoute() - { - // Arrange & Act - var routes = RouteTableFactory.Create(new[] { typeof(MyComponent), }); - - // Assert - Assert.Equal("Test1", Assert.Single(routes.Routes).Template.TemplateText); - } - - [Route("Test1")] - private class MyComponent : ComponentBase - { - } - - [Fact] - public void CanDiscoverRoutes_WithInheritance() - { - // Arrange & Act - var routes = RouteTableFactory.Create(new[] { typeof(MyComponent), typeof(MyInheritedComponent), }); - - // Assert - Assert.Collection( - routes.Routes.OrderBy(r => r.Template.TemplateText), - r => Assert.Equal("Test1", r.Template.TemplateText), - r => Assert.Equal("Test2", r.Template.TemplateText)); - } - - [Route("Test2")] - private class MyInheritedComponent : MyComponent - { - } - - [Fact] - public void CanMatchRootTemplate() - { - // Arrange - var routeTable = new TestRouteTableBuilder().AddRoute("/").Build(); - var context = new RouteContext("/"); - - // Act - routeTable.Route(context); - - // Assert - Assert.NotNull(context.Handler); - } - - [Fact] - public void CanMatchLiteralTemplate() - { - // Arrange - var routeTable = new TestRouteTableBuilder().AddRoute("/literal").Build(); - var context = new RouteContext("/literal/"); - - // Act - routeTable.Route(context); - - // Assert - Assert.NotNull(context.Handler); - } - - [Fact] - public void CanMatchTemplateWithMultipleLiterals() - { - // Arrange - var routeTable = new TestRouteTableBuilder().AddRoute("/some/awesome/route/").Build(); - var context = new RouteContext("/some/awesome/route"); - - // Act - routeTable.Route(context); - - // Assert - Assert.NotNull(context.Handler); - } - - [Fact] - public void RouteMatchingIsCaseInsensitive() - { - // Arrange - var routeTable = new TestRouteTableBuilder().AddRoute("/some/AWESOME/route/").Build(); - var context = new RouteContext("/Some/awesome/RouTe"); - - // Act - routeTable.Route(context); - - // Assert - Assert.NotNull(context.Handler); - } - - [Fact] - public void CanMatchEncodedSegments() - { - // Arrange - var routeTable = new TestRouteTableBuilder().AddRoute("/some/ünicõdē/🛣/").Build(); - var context = new RouteContext("/some/%C3%BCnic%C3%B5d%C4%93/%F0%9F%9B%A3"); - - // Act - routeTable.Route(context); - - // Assert - Assert.NotNull(context.Handler); - } - - [Fact] - public void DoesNotMatchIfSegmentsDontMatch() - { - // Arrange - var routeTable = new TestRouteTableBuilder().AddRoute("/some/AWESOME/route/").Build(); - var context = new RouteContext("/some/brilliant/route"); - - // Act - routeTable.Route(context); - - // Assert - Assert.Null(context.Handler); - } - - [Theory] - [InlineData("/{value:bool}", "/maybe")] - [InlineData("/{value:datetime}", "/1955-01-32")] - [InlineData("/{value:decimal}", "/hello")] - [InlineData("/{value:double}", "/0.1.2")] - [InlineData("/{value:float}", "/0.1.2")] - [InlineData("/{value:guid}", "/not-a-guid")] - [InlineData("/{value:int}", "/3.141")] - [InlineData("/{value:long}", "/3.141")] - public void DoesNotMatchIfConstraintDoesNotMatch(string template, string contextUrl) - { - // Arrange - var routeTable = new TestRouteTableBuilder().AddRoute(template).Build(); - var context = new RouteContext(contextUrl); - - // Act - routeTable.Route(context); - - // Assert - Assert.Null(context.Handler); - } - - [Theory] - [InlineData("/some")] - [InlineData("/some/awesome/route/with/extra/segments")] - public void DoesNotMatchIfDifferentNumberOfSegments(string path) - { - // Arrange - var routeTable = new TestRouteTableBuilder().AddRoute("/some/awesome/route/").Build(); - var context = new RouteContext(path); - - // Act - routeTable.Route(context); - - // Assert - Assert.Null(context.Handler); - } - - [Theory] - [InlineData("/value1", "value1")] - [InlineData("/value2/", "value2")] - [InlineData("/d%C3%A9j%C3%A0%20vu", "déjà vu")] - [InlineData("/d%C3%A9j%C3%A0%20vu/", "déjà vu")] - [InlineData("/d%C3%A9j%C3%A0+vu", "déjà+vu")] - public void CanMatchParameterTemplate(string path, string expectedValue) - { - // Arrange - var routeTable = new TestRouteTableBuilder().AddRoute("/{parameter}").Build(); - var context = new RouteContext(path); - - // Act - routeTable.Route(context); - - // Assert - Assert.NotNull(context.Handler); - Assert.Single(context.Parameters, p => p.Key == "parameter" && (string)p.Value == expectedValue); - } - - [Fact] - public void CanMatchTemplateWithMultipleParameters() - { - // Arrange - var routeTable = new TestRouteTableBuilder().AddRoute("/{some}/awesome/{route}/").Build(); - var context = new RouteContext("/an/awesome/path"); - - var expectedParameters = new Dictionary - { - ["some"] = "an", - ["route"] = "path" - }; - - // Act - routeTable.Route(context); - - // Assert - Assert.NotNull(context.Handler); - Assert.Equal(expectedParameters, context.Parameters); - } - - public static IEnumerable CanMatchParameterWithConstraintCases() => new object[][] - { - new object[] { "/{value:bool}", "/true", true }, - new object[] { "/{value:bool}", "/false", false }, - new object[] { "/{value:datetime}", "/1955-01-30", new DateTime(1955, 1, 30) }, - new object[] { "/{value:decimal}", "/5.3", 5.3m }, - new object[] { "/{value:double}", "/0.1", 0.1d }, - new object[] { "/{value:float}", "/0.1", 0.1f }, - new object[] { "/{value:guid}", "/1FCEF085-884F-416E-B0A1-71B15F3E206B", Guid.Parse("1FCEF085-884F-416E-B0A1-71B15F3E206B") }, - new object[] { "/{value:int}", "/123", 123 }, - new object[] { "/{value:int}", "/-123", -123}, - new object[] { "/{value:long}", "/9223372036854775807", long.MaxValue }, - new object[] { "/{value:long}", $"/-9223372036854775808", long.MinValue }, - }; - - [Theory] - [MemberData(nameof(CanMatchParameterWithConstraintCases))] - public void CanMatchParameterWithConstraint(string template, string contextUrl, object convertedValue) - { - // Arrange - var routeTable = new TestRouteTableBuilder().AddRoute(template).Build(); - var context = new RouteContext(contextUrl); - - // Act - routeTable.Route(context); - - // Assert - if (context.Handler == null) - { - // Make it easier to track down failing tests when using MemberData - throw new InvalidOperationException($"Failed to match template '{template}'."); - } - Assert.Equal(context.Parameters, new Dictionary - { - { "value", convertedValue } - }); - } - - [Fact] - public void CanMatchSegmentWithMultipleConstraints() - { - // Arrange - var routeTable = new TestRouteTableBuilder().AddRoute("/{value:double:int}/").Build(); - var context = new RouteContext("/15"); - - // Act - routeTable.Route(context); - - // Assert - Assert.NotNull(context.Handler); - Assert.Equal(context.Parameters, new Dictionary - { - { "value", 15 } // Final constraint's convertedValue is used - }); - } - - [Fact] - public void PrefersLiteralTemplateOverTemplateWithParameters() - { - // Arrange - var routeTable = new TestRouteTableBuilder() - .AddRoute("/an/awesome/path", typeof(TestHandler1)) - .AddRoute("/{some}/awesome/{route}/", typeof(TestHandler2)) - .Build(); - var context = new RouteContext("/an/awesome/path"); - - // Act - routeTable.Route(context); - - // Assert - Assert.NotNull(context.Handler); - Assert.Null(context.Parameters); - } - - [Fact] - public void PrefersShorterRoutesOverLongerRoutes() - { - // Arrange & Act - var handler = typeof(int); - var routeTable = new TestRouteTableBuilder() - .AddRoute("/an/awesome/path") - .AddRoute("/an/awesome/", handler).Build(); - - // Act - Assert.Equal("an/awesome", routeTable.Routes[0].Template.TemplateText); - } - - [Fact] - public void PrefersMoreConstraintsOverFewer() - { - // Arrange - var routeTable = new TestRouteTableBuilder() - .AddRoute("/products/{id}") - .AddRoute("/products/{id:int}").Build(); - var context = new RouteContext("/products/456"); - - // Act - routeTable.Route(context); - - // Assert - Assert.NotNull(context.Handler); - Assert.Equal(context.Parameters, new Dictionary - { - { "id", 456 } - }); - } - - [Fact] - public void ProducesAStableOrderForNonAmbiguousRoutes() - { - // Arrange & Act - var handler = typeof(int); - var routeTable = new TestRouteTableBuilder() - .AddRoute("/an/awesome/", handler) - .AddRoute("/a/brilliant/").Build(); - - // Act - Assert.Equal("a/brilliant", routeTable.Routes[0].Template.TemplateText); - } - - [Fact] - public void DoesNotThrowIfStableSortComparesRouteWithItself() - { - // Test for https://github.com/aspnet/AspNetCore/issues/13313 - // Arrange & Act - var builder = new TestRouteTableBuilder(); - builder.AddRoute("r16"); - builder.AddRoute("r05"); - builder.AddRoute("r09"); - builder.AddRoute("r00"); - builder.AddRoute("r13"); - builder.AddRoute("r02"); - builder.AddRoute("r03"); - builder.AddRoute("r10"); - builder.AddRoute("r15"); - builder.AddRoute("r14"); - builder.AddRoute("r12"); - builder.AddRoute("r07"); - builder.AddRoute("r11"); - builder.AddRoute("r08"); - builder.AddRoute("r06"); - builder.AddRoute("r04"); - builder.AddRoute("r01"); - - var routeTable = builder.Build(); - - // Act - Assert.Equal(17, routeTable.Routes.Length); - for (var i = 0; i < 17; i++) - { - var templateText = "r" + i.ToString().PadLeft(2, '0'); - Assert.Equal(templateText, routeTable.Routes[i].Template.TemplateText); - } - } - - [Theory] - [InlineData("/literal", "/Literal/")] - [InlineData("/{parameter}", "/{parameter}/")] - [InlineData("/literal/{parameter}", "/Literal/{something}")] - [InlineData("/{parameter}/literal/{something}", "{param}/Literal/{else}")] - public void DetectsAmbiguousRoutes(string left, string right) - { - // Arrange - var expectedMessage = $@"The following routes are ambiguous: -'{left.Trim('/')}' in '{typeof(object).FullName}' -'{right.Trim('/')}' in '{typeof(object).FullName}' -"; - // Act - var exception = Assert.Throws(() => new TestRouteTableBuilder() - .AddRoute(left) - .AddRoute(right).Build()); - - Assert.Equal(expectedMessage, exception.Message); - } - - [Fact] - public void SuppliesNullForUnusedHandlerParameters() - { - // Arrange - var routeTable = new TestRouteTableBuilder() - .AddRoute("/", typeof(TestHandler1)) - .AddRoute("/products/{param1:int}", typeof(TestHandler1)) - .AddRoute("/products/{param2}/{PaRam1}", typeof(TestHandler1)) - .AddRoute("/{unrelated}", typeof(TestHandler2)) - .Build(); - var context = new RouteContext("/products/456"); - - // Act - routeTable.Route(context); - - // Assert - Assert.Collection(routeTable.Routes, - route => - { - Assert.Same(typeof(TestHandler1), route.Handler); - Assert.Equal("/", route.Template.TemplateText); - Assert.Equal(new[] { "param1", "param2" }, route.UnusedRouteParameterNames); - }, - route => - { - Assert.Same(typeof(TestHandler2), route.Handler); - Assert.Equal("{unrelated}", route.Template.TemplateText); - Assert.Equal(Array.Empty(), route.UnusedRouteParameterNames); - }, - route => - { - Assert.Same(typeof(TestHandler1), route.Handler); - Assert.Equal("products/{param1:int}", route.Template.TemplateText); - Assert.Equal(new[] { "param2" }, route.UnusedRouteParameterNames); - }, - route => - { - Assert.Same(typeof(TestHandler1), route.Handler); - Assert.Equal("products/{param2}/{PaRam1}", route.Template.TemplateText); - Assert.Equal(Array.Empty(), route.UnusedRouteParameterNames); - }); - Assert.Same(typeof(TestHandler1), context.Handler); - Assert.Equal(new Dictionary - { - { "param1", 456 }, - { "param2", null }, - }, context.Parameters); - } - - private class TestRouteTableBuilder - { - IList<(string Template, Type Handler)> _routeTemplates = new List<(string, Type)>(); - Type _handler = typeof(object); - - public TestRouteTableBuilder AddRoute(string template, Type handler = null) - { - _routeTemplates.Add((template, handler ?? _handler)); - return this; - } - - public RouteTable Build() - { - try - { - var templatesByHandler = _routeTemplates - .GroupBy(rt => rt.Handler) - .ToDictionary(group => group.Key, group => group.Select(g => g.Template).ToArray()); - return RouteTableFactory.Create(templatesByHandler); - } - catch (InvalidOperationException ex) when (ex.InnerException is InvalidOperationException) - { - // ToArray() will wrap our exception in its own. - throw ex.InnerException; - } - } - } - - class TestHandler1 { } - class TestHandler2 { } - } -} diff --git a/src/Components/Components/test/Routing/TemplateParserTests.cs b/src/Components/Components/test/Routing/TemplateParserTests.cs deleted file mode 100644 index 752963f52d..0000000000 --- a/src/Components/Components/test/Routing/TemplateParserTests.cs +++ /dev/null @@ -1,187 +0,0 @@ -// 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.Collections.Generic; -using System.Linq; -using Xunit; - -namespace Microsoft.AspNetCore.Components.Routing -{ - public class TemplateParserTests - { - [Fact] - public void Parse_SingleLiteral() - { - // Arrange - var expected = new ExpectedTemplateBuilder().Literal("awesome"); - - // Act - var actual = TemplateParser.ParseTemplate("awesome"); - - // Assert - Assert.Equal(expected, actual, RouteTemplateTestComparer.Instance); - } - - [Fact] - public void Parse_SingleParameter() - { - // Arrange - var template = "{p}"; - - var expected = new ExpectedTemplateBuilder().Parameter("p"); - - // Act - var actual = TemplateParser.ParseTemplate(template); - - // Assert - Assert.Equal(expected, actual, RouteTemplateTestComparer.Instance); - } - - [Fact] - public void Parse_MultipleLiterals() - { - // Arrange - var template = "awesome/cool/super"; - - var expected = new ExpectedTemplateBuilder().Literal("awesome").Literal("cool").Literal("super"); - - // Act - var actual = TemplateParser.ParseTemplate(template); - - // Assert - Assert.Equal(expected, actual, RouteTemplateTestComparer.Instance); - } - - [Fact] - public void Parse_MultipleParameters() - { - // Arrange - var template = "{p1}/{p2}/{p3}"; - - var expected = new ExpectedTemplateBuilder().Parameter("p1").Parameter("p2").Parameter("p3"); - - // Act - var actual = TemplateParser.ParseTemplate(template); - - // Assert - Assert.Equal(expected, actual, RouteTemplateTestComparer.Instance); - } - - [Fact] - public void InvalidTemplate_WithRepeatedParameter() - { - var ex = Assert.Throws( - () => TemplateParser.ParseTemplate("{p1}/literal/{p1}")); - - var expectedMessage = "Invalid template '{p1}/literal/{p1}'. The parameter 'Microsoft.AspNetCore.Components.Routing.TemplateSegment' appears multiple times."; - - Assert.Equal(expectedMessage, ex.Message); - } - - [Theory] - [InlineData("p}", "Invalid template 'p}'. Missing '{' in parameter segment 'p}'.")] - [InlineData("{p", "Invalid template '{p'. Missing '}' in parameter segment '{p'.")] - [InlineData("Literal/p}", "Invalid template 'Literal/p}'. Missing '{' in parameter segment 'p}'.")] - [InlineData("Literal/{p", "Invalid template 'Literal/{p'. Missing '}' in parameter segment '{p'.")] - [InlineData("p}/Literal", "Invalid template 'p}/Literal'. Missing '{' in parameter segment 'p}'.")] - [InlineData("{p/Literal", "Invalid template '{p/Literal'. Missing '}' in parameter segment '{p'.")] - [InlineData("Another/p}/Literal", "Invalid template 'Another/p}/Literal'. Missing '{' in parameter segment 'p}'.")] - [InlineData("Another/{p/Literal", "Invalid template 'Another/{p/Literal'. Missing '}' in parameter segment '{p'.")] - - public void InvalidTemplate_WithMismatchedBraces(string template, string expectedMessage) - { - var ex = Assert.Throws( - () => TemplateParser.ParseTemplate(template)); - - Assert.Equal(expectedMessage, ex.Message); - } - - [Theory] - [InlineData("{*}", "Invalid template '{*}'. The character '*' in parameter segment '{*}' is not allowed.")] - [InlineData("{?}", "Invalid template '{?}'. The character '?' in parameter segment '{?}' is not allowed.")] - [InlineData("{{}", "Invalid template '{{}'. The character '{' in parameter segment '{{}' is not allowed.")] - [InlineData("{}}", "Invalid template '{}}'. The character '}' in parameter segment '{}}' is not allowed.")] - [InlineData("{=}", "Invalid template '{=}'. The character '=' in parameter segment '{=}' is not allowed.")] - [InlineData("{.}", "Invalid template '{.}'. The character '.' in parameter segment '{.}' is not allowed.")] - public void ParseRouteParameter_ThrowsIf_ParameterContainsSpecialCharacters(string template, string expectedMessage) - { - // Act & Assert - var ex = Assert.Throws(() => TemplateParser.ParseTemplate(template)); - - Assert.Equal(expectedMessage, ex.Message); - } - - [Fact] - public void InvalidTemplate_InvalidParameterNameWithEmptyNameThrows() - { - var ex = Assert.Throws(() => TemplateParser.ParseTemplate("{a}/{}/{z}")); - - var expectedMessage = "Invalid template '{a}/{}/{z}'. Empty parameter name in segment '{}' is not allowed."; - - Assert.Equal(expectedMessage, ex.Message); - } - - [Fact] - public void InvalidTemplate_ConsecutiveSeparatorsSlashSlashThrows() - { - var ex = Assert.Throws(() => TemplateParser.ParseTemplate("{a}//{z}")); - - var expectedMessage = "Invalid template '{a}//{z}'. Empty segments are not allowed."; - - Assert.Equal(expectedMessage, ex.Message); - } - - private class ExpectedTemplateBuilder - { - public IList Segments { get; set; } = new List(); - - public ExpectedTemplateBuilder Literal(string value) - { - Segments.Add(new TemplateSegment("testtemplate", value, isParameter: false)); - return this; - } - - public ExpectedTemplateBuilder Parameter(string value) - { - Segments.Add(new TemplateSegment("testtemplate", value, isParameter: true)); - return this; - } - - public RouteTemplate Build() => new RouteTemplate(string.Join('/', Segments), Segments.ToArray()); - - public static implicit operator RouteTemplate(ExpectedTemplateBuilder builder) => builder.Build(); - } - - private class RouteTemplateTestComparer : IEqualityComparer - { - public static RouteTemplateTestComparer Instance { get; } = new RouteTemplateTestComparer(); - - public bool Equals(RouteTemplate x, RouteTemplate y) - { - if (x.Segments.Length != y.Segments.Length) - { - return false; - } - - for (var i = 0; i < x.Segments.Length; i++) - { - var xSegment = x.Segments[i]; - var ySegment = y.Segments[i]; - if (xSegment.IsParameter != ySegment.IsParameter) - { - return false; - } - if (!string.Equals(xSegment.Value, ySegment.Value, StringComparison.OrdinalIgnoreCase)) - { - return false; - } - } - - return true; - } - - public int GetHashCode(RouteTemplate obj) => 0; - } - } -} diff --git a/src/Components/Components/test/StackObjectPoolTest.cs b/src/Components/Components/test/StackObjectPoolTest.cs deleted file mode 100644 index 33b9becc05..0000000000 --- a/src/Components/Components/test/StackObjectPoolTest.cs +++ /dev/null @@ -1,123 +0,0 @@ -// 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.Linq; -using Xunit; - -namespace Microsoft.AspNetCore.Components.RenderTree -{ - public class StackObjectPoolTest - { - [Fact] - public void CanGetInstances() - { - // Arrange - var stackObjectPool = new StackObjectPool(10, () => new object()); - - // Act - var instance1 = stackObjectPool.Get(); - var instance2 = stackObjectPool.Get(); - - // Assert - Assert.NotNull(instance1); - Assert.NotNull(instance2); - Assert.NotSame(instance1, instance2); - } - - [Fact] - public void CanReturnInstances() - { - // Arrange - var stackObjectPool = new StackObjectPool(10, () => new object()); - var instance1 = stackObjectPool.Get(); - var instance2 = stackObjectPool.Get(); - - // Act/Assert - // No exception means success - stackObjectPool.Return(instance2); - stackObjectPool.Return(instance1); - } - - [Fact] - public void ReusesInstancesInPoolUpToCapacity() - { - // Arrange - var stackObjectPool = new StackObjectPool(10, () => new object()); - var instance1 = stackObjectPool.Get(); - var instance2 = stackObjectPool.Get(); - stackObjectPool.Return(instance2); - stackObjectPool.Return(instance1); - - // Act - var instance1b = stackObjectPool.Get(); - var instance2b = stackObjectPool.Get(); - var instance3 = stackObjectPool.Get(); - - // Assert - Assert.Same(instance1, instance1b); - Assert.Same(instance2, instance2b); - Assert.NotNull(instance3); - Assert.NotSame(instance1, instance3); - Assert.NotSame(instance2, instance3); - } - - [Fact] - public void SuppliesTransientInstancesWhenExceedingCapacity() - { - // Arrange - var stackObjectPool = new StackObjectPool(1, () => new object()); - - // Act 1: Returns distinct instances beyond capacity - var instance1 = stackObjectPool.Get(); - var instance2 = stackObjectPool.Get(); - var instance3 = stackObjectPool.Get(); - Assert.NotNull(instance1); - Assert.NotNull(instance2); - Assert.NotNull(instance3); - Assert.Equal(3, new[] { instance1, instance2, instance3 }.Distinct().Count()); - - // Act 2: Can return all instances, including transient ones - stackObjectPool.Return(instance3); - stackObjectPool.Return(instance2); - stackObjectPool.Return(instance1); - - // Act 3: Reuses only the non-transient instances - var instance1b = stackObjectPool.Get(); - var instance2b = stackObjectPool.Get(); - Assert.Same(instance1, instance1b); - Assert.NotSame(instance2b, instance2); - Assert.Equal(4, new[] { instance1, instance2, instance3, instance2b }.Distinct().Count()); - } - - [Fact] - public void CannotReturnWhenEmpty() - { - // Arrange - var stackObjectPool = new StackObjectPool(10, () => new object()); - - // Act/Assert - var ex = Assert.Throws(() => - { - stackObjectPool.Return(new object()); - }); - Assert.Equal("There are no outstanding instances to return.", ex.Message); - } - - [Fact] - public void CannotReturnMismatchingTrackedItem() - { - // Arrange - var stackObjectPool = new StackObjectPool(10, () => new object()); - var instance1 = stackObjectPool.Get(); - var instance2 = stackObjectPool.Get(); - - // Act/Assert - var ex = Assert.Throws(() => - { - stackObjectPool.Return(instance1); - }); - Assert.Equal("Attempting to return wrong pooled instance. Get/Return calls must form a stack.", ex.Message); - } - } -} diff --git a/src/Components/ComponentsNoDeps.slnf b/src/Components/ComponentsNoDeps.slnf deleted file mode 100644 index 7e09eeea25..0000000000 --- a/src/Components/ComponentsNoDeps.slnf +++ /dev/null @@ -1,45 +0,0 @@ -{ - "solution": { - "path": "Components.sln", - "projects": [ - "Analyzers\\src\\Microsoft.AspNetCore.Components.Analyzers.csproj", - "Analyzers\\test\\Microsoft.AspNetCore.Components.Analyzers.Tests.csproj", - "Authorization\\src\\Microsoft.AspNetCore.Components.Authorization.csproj", - "Authorization\\test\\Microsoft.AspNetCore.Components.Authorization.Tests.csproj", - "Blazor\\Blazor\\src\\Microsoft.AspNetCore.Blazor.csproj", - "Blazor\\Blazor\\test\\Microsoft.AspNetCore.Blazor.Tests.csproj", - "Blazor\\Build\\src\\Microsoft.AspNetCore.Blazor.Build.csproj", - "Blazor\\Build\\test\\Microsoft.AspNetCore.Blazor.Build.Tests.csproj", - "Blazor\\DevServer\\src\\Microsoft.AspNetCore.Blazor.DevServer.csproj", - "Blazor\\Http\\src\\Microsoft.AspNetCore.Blazor.HttpClient.csproj", - "Blazor\\Http\\test\\Microsoft.AspNetCore.Blazor.HttpClient.Tests.csproj", - "Blazor\\Mono.WebAssembly.Interop\\src\\Mono.WebAssembly.Interop.csproj", - "Blazor\\Server\\src\\Microsoft.AspNetCore.Blazor.Server.csproj", - "Blazor\\Validation\\src\\Microsoft.AspNetCore.Blazor.DataAnnotations.Validation.csproj", - "Blazor\\Validation\\test\\Microsoft.AspNetCore.Blazor.DataAnnotations.Validation.Tests.csproj", - "Blazor\\testassets\\HostedInAspNet.Client\\HostedInAspNet.Client.csproj", - "Blazor\\testassets\\HostedInAspNet.Server\\HostedInAspNet.Server.csproj", - "Blazor\\testassets\\MonoSanityClient\\MonoSanityClient.csproj", - "Blazor\\testassets\\MonoSanity\\MonoSanity.csproj", - "Blazor\\testassets\\StandaloneApp\\StandaloneApp.csproj", - "Components\\perf\\Microsoft.AspNetCore.Components.Performance.csproj", - "Components\\src\\Microsoft.AspNetCore.Components.csproj", - "Components\\test\\Microsoft.AspNetCore.Components.Tests.csproj", - "Forms\\src\\Microsoft.AspNetCore.Components.Forms.csproj", - "Forms\\test\\Microsoft.AspNetCore.Components.Forms.Tests.csproj", - "Ignitor\\src\\Ignitor.csproj", - "Ignitor\\test\\Ignitor.Test.csproj", - "Samples\\BlazorServerApp\\BlazorServerApp.csproj", - "Server\\src\\Microsoft.AspNetCore.Components.Server.csproj", - "Server\\test\\Microsoft.AspNetCore.Components.Server.Tests.csproj", - "Web\\src\\Microsoft.AspNetCore.Components.Web.csproj", - "Web\\test\\Microsoft.AspNetCore.Components.Web.Tests.csproj", - "benchmarkapps\\Wasm.Performance\\Driver\\Wasm.Performance.Driver.csproj", - "benchmarkapps\\Wasm.Performance\\TestApp\\Wasm.Performance.TestApp.csproj", - "test\\E2ETest\\Microsoft.AspNetCore.Components.E2ETests.csproj", - "test\\testassets\\BasicTestApp\\BasicTestApp.csproj", - "test\\testassets\\TestContentPackage\\TestContentPackage.csproj", - "test\\testassets\\TestServer\\Components.TestServer.csproj" - ] - } -} \ No newline at end of file diff --git a/src/Components/Directory.Build.props b/src/Components/Directory.Build.props index ef310ac60d..227faf5fc0 100644 --- a/src/Components/Directory.Build.props +++ b/src/Components/Directory.Build.props @@ -14,7 +14,7 @@ - 3.1.0 + 3.1.2 $(MSBuildThisFileDirectory)Shared\ diff --git a/src/Components/Forms/ref/Microsoft.AspNetCore.Components.Forms.csproj b/src/Components/Forms/ref/Microsoft.AspNetCore.Components.Forms.csproj deleted file mode 100644 index cc3fcfda27..0000000000 --- a/src/Components/Forms/ref/Microsoft.AspNetCore.Components.Forms.csproj +++ /dev/null @@ -1,15 +0,0 @@ - - - - netstandard2.0;$(DefaultNetCoreTargetFramework) - - - - - - - - - - - diff --git a/src/Components/Forms/ref/Microsoft.AspNetCore.Components.Forms.netcoreapp.cs b/src/Components/Forms/ref/Microsoft.AspNetCore.Components.Forms.netcoreapp.cs deleted file mode 100644 index 4674ff0fb4..0000000000 --- a/src/Components/Forms/ref/Microsoft.AspNetCore.Components.Forms.netcoreapp.cs +++ /dev/null @@ -1,75 +0,0 @@ -// 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. - -namespace Microsoft.AspNetCore.Components.Forms -{ - public partial class DataAnnotationsValidator : Microsoft.AspNetCore.Components.ComponentBase - { - public DataAnnotationsValidator() { } - protected override void OnInitialized() { } - } - public sealed partial class EditContext - { - public EditContext(object model) { } - public object Model { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - public event System.EventHandler OnFieldChanged { add { } remove { } } - public event System.EventHandler OnValidationRequested { add { } remove { } } - public event System.EventHandler OnValidationStateChanged { add { } remove { } } - public Microsoft.AspNetCore.Components.Forms.FieldIdentifier Field(string fieldName) { throw null; } - public System.Collections.Generic.IEnumerable GetValidationMessages() { throw null; } - public System.Collections.Generic.IEnumerable GetValidationMessages(Microsoft.AspNetCore.Components.Forms.FieldIdentifier fieldIdentifier) { throw null; } - public System.Collections.Generic.IEnumerable GetValidationMessages(System.Linq.Expressions.Expression> accessor) { throw null; } - public bool IsModified() { throw null; } - public bool IsModified(in Microsoft.AspNetCore.Components.Forms.FieldIdentifier fieldIdentifier) { throw null; } - public bool IsModified(System.Linq.Expressions.Expression> accessor) { throw null; } - public void MarkAsUnmodified() { } - public void MarkAsUnmodified(in Microsoft.AspNetCore.Components.Forms.FieldIdentifier fieldIdentifier) { } - public void NotifyFieldChanged(in Microsoft.AspNetCore.Components.Forms.FieldIdentifier fieldIdentifier) { } - public void NotifyValidationStateChanged() { } - public bool Validate() { throw null; } - } - public static partial class EditContextDataAnnotationsExtensions - { - public static Microsoft.AspNetCore.Components.Forms.EditContext AddDataAnnotationsValidation(this Microsoft.AspNetCore.Components.Forms.EditContext editContext) { throw null; } - } - public sealed partial class FieldChangedEventArgs : System.EventArgs - { - public FieldChangedEventArgs(in Microsoft.AspNetCore.Components.Forms.FieldIdentifier fieldIdentifier) { } - public Microsoft.AspNetCore.Components.Forms.FieldIdentifier FieldIdentifier { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - } - [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] - public readonly partial struct FieldIdentifier : System.IEquatable - { - private readonly object _dummy; - public FieldIdentifier(object model, string fieldName) { throw null; } - public string FieldName { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - public object Model { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - public static Microsoft.AspNetCore.Components.Forms.FieldIdentifier Create(System.Linq.Expressions.Expression> accessor) { throw null; } - public bool Equals(Microsoft.AspNetCore.Components.Forms.FieldIdentifier otherIdentifier) { throw null; } - public override bool Equals(object obj) { throw null; } - public override int GetHashCode() { throw null; } - } - public sealed partial class ValidationMessageStore - { - public ValidationMessageStore(Microsoft.AspNetCore.Components.Forms.EditContext editContext) { } - public System.Collections.Generic.IEnumerable this[Microsoft.AspNetCore.Components.Forms.FieldIdentifier fieldIdentifier] { get { throw null; } } - public System.Collections.Generic.IEnumerable this[System.Linq.Expressions.Expression> accessor] { get { throw null; } } - public void Add(in Microsoft.AspNetCore.Components.Forms.FieldIdentifier fieldIdentifier, System.Collections.Generic.IEnumerable messages) { } - public void Add(in Microsoft.AspNetCore.Components.Forms.FieldIdentifier fieldIdentifier, string message) { } - public void Add(System.Linq.Expressions.Expression> accessor, System.Collections.Generic.IEnumerable messages) { } - public void Add(System.Linq.Expressions.Expression> accessor, string message) { } - public void Clear() { } - public void Clear(in Microsoft.AspNetCore.Components.Forms.FieldIdentifier fieldIdentifier) { } - public void Clear(System.Linq.Expressions.Expression> accessor) { } - } - public sealed partial class ValidationRequestedEventArgs : System.EventArgs - { - public static readonly new Microsoft.AspNetCore.Components.Forms.ValidationRequestedEventArgs Empty; - public ValidationRequestedEventArgs() { } - } - public sealed partial class ValidationStateChangedEventArgs : System.EventArgs - { - public static readonly new Microsoft.AspNetCore.Components.Forms.ValidationStateChangedEventArgs Empty; - public ValidationStateChangedEventArgs() { } - } -} diff --git a/src/Components/Forms/ref/Microsoft.AspNetCore.Components.Forms.netstandard2.0.cs b/src/Components/Forms/ref/Microsoft.AspNetCore.Components.Forms.netstandard2.0.cs deleted file mode 100644 index 4674ff0fb4..0000000000 --- a/src/Components/Forms/ref/Microsoft.AspNetCore.Components.Forms.netstandard2.0.cs +++ /dev/null @@ -1,75 +0,0 @@ -// 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. - -namespace Microsoft.AspNetCore.Components.Forms -{ - public partial class DataAnnotationsValidator : Microsoft.AspNetCore.Components.ComponentBase - { - public DataAnnotationsValidator() { } - protected override void OnInitialized() { } - } - public sealed partial class EditContext - { - public EditContext(object model) { } - public object Model { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - public event System.EventHandler OnFieldChanged { add { } remove { } } - public event System.EventHandler OnValidationRequested { add { } remove { } } - public event System.EventHandler OnValidationStateChanged { add { } remove { } } - public Microsoft.AspNetCore.Components.Forms.FieldIdentifier Field(string fieldName) { throw null; } - public System.Collections.Generic.IEnumerable GetValidationMessages() { throw null; } - public System.Collections.Generic.IEnumerable GetValidationMessages(Microsoft.AspNetCore.Components.Forms.FieldIdentifier fieldIdentifier) { throw null; } - public System.Collections.Generic.IEnumerable GetValidationMessages(System.Linq.Expressions.Expression> accessor) { throw null; } - public bool IsModified() { throw null; } - public bool IsModified(in Microsoft.AspNetCore.Components.Forms.FieldIdentifier fieldIdentifier) { throw null; } - public bool IsModified(System.Linq.Expressions.Expression> accessor) { throw null; } - public void MarkAsUnmodified() { } - public void MarkAsUnmodified(in Microsoft.AspNetCore.Components.Forms.FieldIdentifier fieldIdentifier) { } - public void NotifyFieldChanged(in Microsoft.AspNetCore.Components.Forms.FieldIdentifier fieldIdentifier) { } - public void NotifyValidationStateChanged() { } - public bool Validate() { throw null; } - } - public static partial class EditContextDataAnnotationsExtensions - { - public static Microsoft.AspNetCore.Components.Forms.EditContext AddDataAnnotationsValidation(this Microsoft.AspNetCore.Components.Forms.EditContext editContext) { throw null; } - } - public sealed partial class FieldChangedEventArgs : System.EventArgs - { - public FieldChangedEventArgs(in Microsoft.AspNetCore.Components.Forms.FieldIdentifier fieldIdentifier) { } - public Microsoft.AspNetCore.Components.Forms.FieldIdentifier FieldIdentifier { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - } - [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] - public readonly partial struct FieldIdentifier : System.IEquatable - { - private readonly object _dummy; - public FieldIdentifier(object model, string fieldName) { throw null; } - public string FieldName { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - public object Model { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - public static Microsoft.AspNetCore.Components.Forms.FieldIdentifier Create(System.Linq.Expressions.Expression> accessor) { throw null; } - public bool Equals(Microsoft.AspNetCore.Components.Forms.FieldIdentifier otherIdentifier) { throw null; } - public override bool Equals(object obj) { throw null; } - public override int GetHashCode() { throw null; } - } - public sealed partial class ValidationMessageStore - { - public ValidationMessageStore(Microsoft.AspNetCore.Components.Forms.EditContext editContext) { } - public System.Collections.Generic.IEnumerable this[Microsoft.AspNetCore.Components.Forms.FieldIdentifier fieldIdentifier] { get { throw null; } } - public System.Collections.Generic.IEnumerable this[System.Linq.Expressions.Expression> accessor] { get { throw null; } } - public void Add(in Microsoft.AspNetCore.Components.Forms.FieldIdentifier fieldIdentifier, System.Collections.Generic.IEnumerable messages) { } - public void Add(in Microsoft.AspNetCore.Components.Forms.FieldIdentifier fieldIdentifier, string message) { } - public void Add(System.Linq.Expressions.Expression> accessor, System.Collections.Generic.IEnumerable messages) { } - public void Add(System.Linq.Expressions.Expression> accessor, string message) { } - public void Clear() { } - public void Clear(in Microsoft.AspNetCore.Components.Forms.FieldIdentifier fieldIdentifier) { } - public void Clear(System.Linq.Expressions.Expression> accessor) { } - } - public sealed partial class ValidationRequestedEventArgs : System.EventArgs - { - public static readonly new Microsoft.AspNetCore.Components.Forms.ValidationRequestedEventArgs Empty; - public ValidationRequestedEventArgs() { } - } - public sealed partial class ValidationStateChangedEventArgs : System.EventArgs - { - public static readonly new Microsoft.AspNetCore.Components.Forms.ValidationStateChangedEventArgs Empty; - public ValidationStateChangedEventArgs() { } - } -} diff --git a/src/Components/Forms/src/DataAnnotationsValidator.cs b/src/Components/Forms/src/DataAnnotationsValidator.cs deleted file mode 100644 index 63696d2c79..0000000000 --- a/src/Components/Forms/src/DataAnnotationsValidator.cs +++ /dev/null @@ -1,28 +0,0 @@ -// 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.AspNetCore.Components.Forms -{ - /// - /// Adds Data Annotations validation support to an . - /// - public class DataAnnotationsValidator : ComponentBase - { - [CascadingParameter] EditContext CurrentEditContext { get; set; } - - /// - protected override void OnInitialized() - { - if (CurrentEditContext == null) - { - throw new InvalidOperationException($"{nameof(DataAnnotationsValidator)} requires a cascading " + - $"parameter of type {nameof(EditContext)}. For example, you can use {nameof(DataAnnotationsValidator)} " + - $"inside an EditForm."); - } - - CurrentEditContext.AddDataAnnotationsValidation(); - } - } -} diff --git a/src/Components/Forms/src/EditContext.cs b/src/Components/Forms/src/EditContext.cs deleted file mode 100644 index caaf677c37..0000000000 --- a/src/Components/Forms/src/EditContext.cs +++ /dev/null @@ -1,210 +0,0 @@ -// 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.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; - -namespace Microsoft.AspNetCore.Components.Forms -{ - /// - /// Holds metadata related to a data editing process, such as flags to indicate which - /// fields have been modified and the current set of validation messages. - /// - public sealed class EditContext - { - // Note that EditContext tracks state for any FieldIdentifier you give to it, plus - // the underlying storage is sparse. As such, none of the APIs have a "field not found" - // error state. If you give us an unrecognized FieldIdentifier, that just means we - // didn't yet track any state for it, so we behave as if it's in the default state - // (valid and unmodified). - private readonly Dictionary _fieldStates = new Dictionary(); - - /// - /// Constructs an instance of . - /// - /// The model object for the . This object should hold the data being edited, for example as a set of properties. - public EditContext(object model) - { - // The only reason we disallow null is because you'd almost always want one, and if you - // really don't, you can pass an empty object then ignore it. Ensuring it's nonnull - // simplifies things for all consumers of EditContext. - Model = model ?? throw new ArgumentNullException(nameof(model)); - } - - /// - /// An event that is raised when a field value changes. - /// - public event EventHandler OnFieldChanged; - - /// - /// An event that is raised when validation is requested. - /// - public event EventHandler OnValidationRequested; - - /// - /// An event that is raised when validation state has changed. - /// - public event EventHandler OnValidationStateChanged; - - /// - /// Supplies a corresponding to a specified field name - /// on this 's . - /// - /// The name of the editable field. - /// A corresponding to a specified field name on this 's . - public FieldIdentifier Field(string fieldName) - => new FieldIdentifier(Model, fieldName); - - /// - /// Gets the model object for this . - /// - public object Model { get; } - - /// - /// Signals that the value for the specified field has changed. - /// - /// Identifies the field whose value has been changed. - public void NotifyFieldChanged(in FieldIdentifier fieldIdentifier) - { - GetFieldState(fieldIdentifier, ensureExists: true).IsModified = true; - OnFieldChanged?.Invoke(this, new FieldChangedEventArgs(fieldIdentifier)); - } - - /// - /// Signals that some aspect of validation state has changed. - /// - public void NotifyValidationStateChanged() - { - OnValidationStateChanged?.Invoke(this, ValidationStateChangedEventArgs.Empty); - } - - /// - /// Clears any modification flag that may be tracked for the specified field. - /// - /// Identifies the field whose modification flag (if any) should be cleared. - public void MarkAsUnmodified(in FieldIdentifier fieldIdentifier) - { - if (_fieldStates.TryGetValue(fieldIdentifier, out var state)) - { - state.IsModified = false; - } - } - - /// - /// Clears all modification flags within this . - /// - public void MarkAsUnmodified() - { - foreach (var state in _fieldStates) - { - state.Value.IsModified = false; - } - } - - /// - /// Determines whether any of the fields in this have been modified. - /// - /// True if any of the fields in this have been modified; otherwise false. - public bool IsModified() - { - // If necessary, we could consider caching the overall "is modified" state and only recomputing - // when there's a call to NotifyFieldModified/NotifyFieldUnmodified - foreach (var state in _fieldStates) - { - if (state.Value.IsModified) - { - return true; - } - } - - return false; - } - - /// - /// Gets the current validation messages across all fields. - /// - /// This method does not perform validation itself. It only returns messages determined by previous validation actions. - /// - /// The current validation messages. - public IEnumerable GetValidationMessages() - { - // Since we're only enumerating the fields for which we have a non-null state, the cost of this grows - // based on how many fields have been modified or have associated validation messages - foreach (var state in _fieldStates) - { - foreach (var message in state.Value.GetValidationMessages()) - { - yield return message; - } - } - } - - /// - /// Gets the current validation messages for the specified field. - /// - /// This method does not perform validation itself. It only returns messages determined by previous validation actions. - /// - /// Identifies the field whose current validation messages should be returned. - /// The current validation messages for the specified field. - public IEnumerable GetValidationMessages(FieldIdentifier fieldIdentifier) - { - if (_fieldStates.TryGetValue(fieldIdentifier, out var state)) - { - foreach (var message in state.GetValidationMessages()) - { - yield return message; - } - } - } - - /// - /// Gets the current validation messages for the specified field. - /// - /// This method does not perform validation itself. It only returns messages determined by previous validation actions. - /// - /// Identifies the field whose current validation messages should be returned. - /// The current validation messages for the specified field. - public IEnumerable GetValidationMessages(Expression> accessor) - => GetValidationMessages(FieldIdentifier.Create(accessor)); - - /// - /// Determines whether the specified fields in this has been modified. - /// - /// True if the field has been modified; otherwise false. - public bool IsModified(in FieldIdentifier fieldIdentifier) - => _fieldStates.TryGetValue(fieldIdentifier, out var state) - ? state.IsModified - : false; - - /// - /// Determines whether the specified fields in this has been modified. - /// - /// Identifies the field whose current validation messages should be returned. - /// True if the field has been modified; otherwise false. - public bool IsModified(Expression> accessor) - => IsModified(FieldIdentifier.Create(accessor)); - - /// - /// Validates this . - /// - /// True if there are no validation messages after validation; otherwise false. - public bool Validate() - { - OnValidationRequested?.Invoke(this, ValidationRequestedEventArgs.Empty); - return !GetValidationMessages().Any(); - } - - internal FieldState GetFieldState(in FieldIdentifier fieldIdentifier, bool ensureExists) - { - if (!_fieldStates.TryGetValue(fieldIdentifier, out var state) && ensureExists) - { - state = new FieldState(fieldIdentifier); - _fieldStates.Add(fieldIdentifier, state); - } - - return state; - } - } -} diff --git a/src/Components/Forms/src/EditContextDataAnnotationsExtensions.cs b/src/Components/Forms/src/EditContextDataAnnotationsExtensions.cs deleted file mode 100644 index e7f9d5f155..0000000000 --- a/src/Components/Forms/src/EditContextDataAnnotationsExtensions.cs +++ /dev/null @@ -1,107 +0,0 @@ -// 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.Collections.Concurrent; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.Linq; -using System.Reflection; - -namespace Microsoft.AspNetCore.Components.Forms -{ - /// - /// Extension methods to add DataAnnotations validation to an . - /// - public static class EditContextDataAnnotationsExtensions - { - private static ConcurrentDictionary<(Type ModelType, string FieldName), PropertyInfo> _propertyInfoCache - = new ConcurrentDictionary<(Type, string), PropertyInfo>(); - - /// - /// Adds DataAnnotations validation support to the . - /// - /// The . - public static EditContext AddDataAnnotationsValidation(this EditContext editContext) - { - if (editContext == null) - { - throw new ArgumentNullException(nameof(editContext)); - } - - var messages = new ValidationMessageStore(editContext); - - // Perform object-level validation on request - editContext.OnValidationRequested += - (sender, eventArgs) => ValidateModel((EditContext)sender, messages); - - // Perform per-field validation on each field edit - editContext.OnFieldChanged += - (sender, eventArgs) => ValidateField(editContext, messages, eventArgs.FieldIdentifier); - - return editContext; - } - - private static void ValidateModel(EditContext editContext, ValidationMessageStore messages) - { - var validationContext = new ValidationContext(editContext.Model); - var validationResults = new List(); - Validator.TryValidateObject(editContext.Model, validationContext, validationResults, true); - - // Transfer results to the ValidationMessageStore - messages.Clear(); - foreach (var validationResult in validationResults) - { - if (!validationResult.MemberNames.Any()) - { - messages.Add(new FieldIdentifier(editContext.Model, fieldName: string.Empty), validationResult.ErrorMessage); - continue; - } - - foreach (var memberName in validationResult.MemberNames) - { - messages.Add(editContext.Field(memberName), validationResult.ErrorMessage); - } - } - - editContext.NotifyValidationStateChanged(); - } - - private static void ValidateField(EditContext editContext, ValidationMessageStore messages, in FieldIdentifier fieldIdentifier) - { - if (TryGetValidatableProperty(fieldIdentifier, out var propertyInfo)) - { - var propertyValue = propertyInfo.GetValue(fieldIdentifier.Model); - var validationContext = new ValidationContext(fieldIdentifier.Model) - { - MemberName = propertyInfo.Name - }; - var results = new List(); - - Validator.TryValidateProperty(propertyValue, validationContext, results); - messages.Clear(fieldIdentifier); - messages.Add(fieldIdentifier, results.Select(result => result.ErrorMessage)); - - // We have to notify even if there were no messages before and are still no messages now, - // because the "state" that changed might be the completion of some async validation task - editContext.NotifyValidationStateChanged(); - } - } - - private static bool TryGetValidatableProperty(in FieldIdentifier fieldIdentifier, out PropertyInfo propertyInfo) - { - var cacheKey = (ModelType: fieldIdentifier.Model.GetType(), fieldIdentifier.FieldName); - if (!_propertyInfoCache.TryGetValue(cacheKey, out propertyInfo)) - { - // DataAnnotations only validates public properties, so that's all we'll look for - // If we can't find it, cache 'null' so we don't have to try again next time - propertyInfo = cacheKey.ModelType.GetProperty(cacheKey.FieldName); - - // No need to lock, because it doesn't matter if we write the same value twice - _propertyInfoCache[cacheKey] = propertyInfo; - } - - return propertyInfo != null; - } - } -} diff --git a/src/Components/Forms/src/FieldChangedEventArgs.cs b/src/Components/Forms/src/FieldChangedEventArgs.cs deleted file mode 100644 index 780a91a01d..0000000000 --- a/src/Components/Forms/src/FieldChangedEventArgs.cs +++ /dev/null @@ -1,27 +0,0 @@ -// 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.AspNetCore.Components.Forms -{ - /// - /// Provides information about the event. - /// - public sealed class FieldChangedEventArgs : EventArgs - { - /// - /// Creates a new instance of . - /// - /// The - public FieldChangedEventArgs(in FieldIdentifier fieldIdentifier) - { - FieldIdentifier = fieldIdentifier; - } - - /// - /// Identifies the field whose value has changed. - /// - public FieldIdentifier FieldIdentifier { get; } - } -} diff --git a/src/Components/Forms/src/FieldIdentifier.cs b/src/Components/Forms/src/FieldIdentifier.cs deleted file mode 100644 index 1c2c923d38..0000000000 --- a/src/Components/Forms/src/FieldIdentifier.cs +++ /dev/null @@ -1,121 +0,0 @@ -// 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.Linq.Expressions; - -namespace Microsoft.AspNetCore.Components.Forms -{ - /// - /// Uniquely identifies a single field that can be edited. This may correspond to a property on a - /// model object, or can be any other named value. - /// - public readonly struct FieldIdentifier : IEquatable - { - /// - /// Initializes a new instance of the structure. - /// - /// An expression that identifies an object member. - /// The field . - public static FieldIdentifier Create(Expression> accessor) - { - if (accessor == null) - { - throw new ArgumentNullException(nameof(accessor)); - } - - ParseAccessor(accessor, out var model, out var fieldName); - return new FieldIdentifier(model, fieldName); - } - - /// - /// Initializes a new instance of the structure. - /// - /// The object that owns the field. - /// The name of the editable field. - public FieldIdentifier(object model, string fieldName) - { - if (model == null) - { - throw new ArgumentNullException(nameof(model)); - } - - if (model.GetType().IsValueType) - { - throw new ArgumentException("The model must be a reference-typed object.", nameof(model)); - } - - Model = model; - - // Note that we do allow an empty string. This is used by some validation systems - // as a place to store object-level (not per-property) messages. - FieldName = fieldName ?? throw new ArgumentNullException(nameof(fieldName)); - } - - /// - /// Gets the object that owns the editable field. - /// - public object Model { get; } - - /// - /// Gets the name of the editable field. - /// - public string FieldName { get; } - - /// - public override int GetHashCode() - => (Model, FieldName).GetHashCode(); - - /// - public override bool Equals(object obj) - => obj is FieldIdentifier otherIdentifier - && Equals(otherIdentifier); - - /// - public bool Equals(FieldIdentifier otherIdentifier) - { - return - otherIdentifier.Model == Model && - string.Equals(otherIdentifier.FieldName, FieldName, StringComparison.Ordinal); - } - - private static void ParseAccessor(Expression> accessor, out object model, out string fieldName) - { - var accessorBody = accessor.Body; - - // Unwrap casts to object - if (accessorBody is UnaryExpression unaryExpression - && unaryExpression.NodeType == ExpressionType.Convert - && unaryExpression.Type == typeof(object)) - { - accessorBody = unaryExpression.Operand; - } - - if (!(accessorBody is MemberExpression memberExpression)) - { - throw new ArgumentException($"The provided expression contains a {accessorBody.GetType().Name} which is not supported. {nameof(FieldIdentifier)} only supports simple member accessors (fields, properties) of an object."); - } - - // Identify the field name. We don't mind whether it's a property or field, or even something else. - fieldName = memberExpression.Member.Name; - - // Get a reference to the model object - // i.e., given an value like "(something).MemberName", determine the runtime value of "(something)", - switch (memberExpression.Expression) - { - case ConstantExpression constantExpression: - model = constantExpression.Value; - break; - default: - // It would be great to cache this somehow, but it's unclear there's a reasonable way to do - // so, given that it embeds captured values such as "this". We could consider special-casing - // for "() => something.Member" and building a cache keyed by "something.GetType()" with values - // of type Func so we can cheaply map from "something" to "something.Member". - var modelLambda = Expression.Lambda(memberExpression.Expression); - var modelLambdaCompiled = (Func)modelLambda.Compile(); - model = modelLambdaCompiled(); - break; - } - } - } -} diff --git a/src/Components/Forms/src/FieldState.cs b/src/Components/Forms/src/FieldState.cs deleted file mode 100644 index 3a8d1f0eb3..0000000000 --- a/src/Components/Forms/src/FieldState.cs +++ /dev/null @@ -1,52 +0,0 @@ -// 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.Collections.Generic; - -namespace Microsoft.AspNetCore.Components.Forms -{ - internal class FieldState - { - private readonly FieldIdentifier _fieldIdentifier; - - // We track which ValidationMessageStore instances have a nonempty set of messages for this field so that - // we can quickly evaluate the list of messages for the field without having to query all stores. This is - // relevant because each validation component may define its own message store, so there might be as many - // stores are there are fields or UI elements. - private HashSet _validationMessageStores; - - public FieldState(FieldIdentifier fieldIdentifier) - { - _fieldIdentifier = fieldIdentifier; - } - - public bool IsModified { get; set; } - - public IEnumerable GetValidationMessages() - { - if (_validationMessageStores != null) - { - foreach (var store in _validationMessageStores) - { - foreach (var message in store[_fieldIdentifier]) - { - yield return message; - } - } - } - } - - public void AssociateWithValidationMessageStore(ValidationMessageStore validationMessageStore) - { - if (_validationMessageStores == null) - { - _validationMessageStores = new HashSet(); - } - - _validationMessageStores.Add(validationMessageStore); - } - - public void DissociateFromValidationMessageStore(ValidationMessageStore validationMessageStore) - => _validationMessageStores?.Remove(validationMessageStore); - } -} diff --git a/src/Components/Forms/src/Microsoft.AspNetCore.Components.Forms.csproj b/src/Components/Forms/src/Microsoft.AspNetCore.Components.Forms.csproj deleted file mode 100644 index d338f21000..0000000000 --- a/src/Components/Forms/src/Microsoft.AspNetCore.Components.Forms.csproj +++ /dev/null @@ -1,20 +0,0 @@ - - - - netstandard2.0;$(DefaultNetCoreTargetFramework) - $(DefaultNetCoreTargetFramework) - true - Forms and validation support for Blazor applications. - true - true - - - - - - - - - - - diff --git a/src/Components/Forms/src/ValidationMessageStore.cs b/src/Components/Forms/src/ValidationMessageStore.cs deleted file mode 100644 index a8b0664bec..0000000000 --- a/src/Components/Forms/src/ValidationMessageStore.cs +++ /dev/null @@ -1,128 +0,0 @@ -// 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.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; - -namespace Microsoft.AspNetCore.Components.Forms -{ - /// - /// Holds validation messages for an . - /// - public sealed class ValidationMessageStore - { - private readonly EditContext _editContext; - private readonly Dictionary> _messages = new Dictionary>(); - - /// - /// Creates an instance of . - /// - /// The with which this store should be associated. - public ValidationMessageStore(EditContext editContext) - { - _editContext = editContext ?? throw new ArgumentNullException(nameof(editContext)); - } - - /// - /// Adds a validation message for the specified field. - /// - /// The identifier for the field. - /// The validation message. - public void Add(in FieldIdentifier fieldIdentifier, string message) - => GetOrCreateMessagesListForField(fieldIdentifier).Add(message); - - /// - /// Adds a validation message for the specified field. - /// - /// Identifies the field for which to add the message. - /// The validation message. - public void Add(Expression> accessor, string message) - => Add(FieldIdentifier.Create(accessor), message); - - /// - /// Adds the messages from the specified collection for the specified field. - /// - /// The identifier for the field. - /// The validation messages to be added. - public void Add(in FieldIdentifier fieldIdentifier, IEnumerable messages) - => GetOrCreateMessagesListForField(fieldIdentifier).AddRange(messages); - - /// - /// Adds the messages from the specified collection for the specified field. - /// - /// Identifies the field for which to add the messages. - /// The validation messages to be added. - public void Add(Expression> accessor, IEnumerable messages) - => Add(FieldIdentifier.Create(accessor), messages); - - /// - /// Gets the validation messages within this for the specified field. - /// - /// To get the validation messages across all validation message stores, use instead - /// - /// The identifier for the field. - /// The validation messages for the specified field within this . - public IEnumerable this[FieldIdentifier fieldIdentifier] - => _messages.TryGetValue(fieldIdentifier, out var messages) ? messages : Enumerable.Empty(); - - /// - /// Gets the validation messages within this for the specified field. - /// - /// To get the validation messages across all validation message stores, use instead - /// - /// The identifier for the field. - /// The validation messages for the specified field within this . - public IEnumerable this[Expression> accessor] - => this[FieldIdentifier.Create(accessor)]; - - /// - /// Removes all messages within this . - /// - public void Clear() - { - foreach (var fieldIdentifier in _messages.Keys) - { - DissociateFromField(fieldIdentifier); - } - - _messages.Clear(); - } - - /// - /// Removes all messages within this for the specified field. - /// - /// Identifies the field for which to remove the messages. - public void Clear(Expression> accessor) - => Clear(FieldIdentifier.Create(accessor)); - - /// - /// Removes all messages within this for the specified field. - /// - /// The identifier for the field. - public void Clear(in FieldIdentifier fieldIdentifier) - { - DissociateFromField(fieldIdentifier); - _messages.Remove(fieldIdentifier); - } - - private List GetOrCreateMessagesListForField(in FieldIdentifier fieldIdentifier) - { - if (!_messages.TryGetValue(fieldIdentifier, out var messagesForField)) - { - messagesForField = new List(); - _messages.Add(fieldIdentifier, messagesForField); - AssociateWithField(fieldIdentifier); - } - - return messagesForField; - } - - private void AssociateWithField(in FieldIdentifier fieldIdentifier) - => _editContext.GetFieldState(fieldIdentifier, ensureExists: true).AssociateWithValidationMessageStore(this); - - private void DissociateFromField(in FieldIdentifier fieldIdentifier) - => _editContext.GetFieldState(fieldIdentifier, ensureExists: false)?.DissociateFromValidationMessageStore(this); - } -} diff --git a/src/Components/Forms/src/ValidationRequestedEventArgs.cs b/src/Components/Forms/src/ValidationRequestedEventArgs.cs deleted file mode 100644 index 52efde8de5..0000000000 --- a/src/Components/Forms/src/ValidationRequestedEventArgs.cs +++ /dev/null @@ -1,25 +0,0 @@ -// 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.AspNetCore.Components.Forms -{ - /// - /// Provides information about the event. - /// - public sealed class ValidationRequestedEventArgs : EventArgs - { - /// - /// Gets a shared empty instance of . - /// - public static new readonly ValidationRequestedEventArgs Empty = new ValidationRequestedEventArgs(); - - /// - /// Creates a new instance of . - /// - public ValidationRequestedEventArgs() - { - } - } -} diff --git a/src/Components/Forms/src/ValidationStateChangedEventArgs.cs b/src/Components/Forms/src/ValidationStateChangedEventArgs.cs deleted file mode 100644 index fd8dbb8d69..0000000000 --- a/src/Components/Forms/src/ValidationStateChangedEventArgs.cs +++ /dev/null @@ -1,25 +0,0 @@ -// 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.AspNetCore.Components.Forms -{ - /// - /// Provides information about the event. - /// - public sealed class ValidationStateChangedEventArgs : EventArgs - { - /// - /// Gets a shared empty instance of . - /// - public new static readonly ValidationStateChangedEventArgs Empty = new ValidationStateChangedEventArgs(); - - /// - /// Creates a new instance of - /// - public ValidationStateChangedEventArgs() - { - } - } -} diff --git a/src/Components/Forms/test/EditContextDataAnnotationsExtensionsTest.cs b/src/Components/Forms/test/EditContextDataAnnotationsExtensionsTest.cs deleted file mode 100644 index bb7837e2f0..0000000000 --- a/src/Components/Forms/test/EditContextDataAnnotationsExtensionsTest.cs +++ /dev/null @@ -1,170 +0,0 @@ -// 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.ComponentModel.DataAnnotations; -using Xunit; - -namespace Microsoft.AspNetCore.Components.Forms -{ - public class EditContextDataAnnotationsExtensionsTest - { - [Fact] - public void CannotUseNullEditContext() - { - var editContext = (EditContext)null; - var ex = Assert.Throws(() => editContext.AddDataAnnotationsValidation()); - Assert.Equal("editContext", ex.ParamName); - } - - [Fact] - public void ReturnsEditContextForChaining() - { - var editContext = new EditContext(new object()); - var returnValue = editContext.AddDataAnnotationsValidation(); - Assert.Same(editContext, returnValue); - } - - [Fact] - public void GetsValidationMessagesFromDataAnnotations() - { - // Arrange - var model = new TestModel { IntFrom1To100 = 101 }; - var editContext = new EditContext(model).AddDataAnnotationsValidation(); - - // Act - var isValid = editContext.Validate(); - - // Assert - Assert.False(isValid); - - Assert.Equal(new string[] - { - "RequiredString:required", - "IntFrom1To100:range" - }, - editContext.GetValidationMessages()); - - Assert.Equal(new string[] { "RequiredString:required" }, - editContext.GetValidationMessages(editContext.Field(nameof(TestModel.RequiredString)))); - - // This shows we're including non-[Required] properties in the validation results, i.e, - // that we're correctly passing "validateAllProperties: true" to DataAnnotations - Assert.Equal(new string[] { "IntFrom1To100:range" }, - editContext.GetValidationMessages(editContext.Field(nameof(TestModel.IntFrom1To100)))); - } - - [Fact] - public void ClearsExistingValidationMessagesOnFurtherRuns() - { - // Arrange - var model = new TestModel { IntFrom1To100 = 101 }; - var editContext = new EditContext(model).AddDataAnnotationsValidation(); - - // Act/Assert 1: Initially invalid - Assert.False(editContext.Validate()); - - // Act/Assert 2: Can become valid - model.RequiredString = "Hello"; - model.IntFrom1To100 = 100; - Assert.True(editContext.Validate()); - } - - [Fact] - public void NotifiesValidationStateChangedAfterObjectValidation() - { - // Arrange - var model = new TestModel { IntFrom1To100 = 101 }; - var editContext = new EditContext(model).AddDataAnnotationsValidation(); - var onValidationStateChangedCount = 0; - editContext.OnValidationStateChanged += (sender, eventArgs) => onValidationStateChangedCount++; - - // Act/Assert 1: Notifies after invalid results - Assert.False(editContext.Validate()); - Assert.Equal(1, onValidationStateChangedCount); - - // Act/Assert 2: Notifies after valid results - model.RequiredString = "Hello"; - model.IntFrom1To100 = 100; - Assert.True(editContext.Validate()); - Assert.Equal(2, onValidationStateChangedCount); - - // Act/Assert 3: Notifies even if results haven't changed. Later we might change the - // logic to track the previous results and compare with the new ones, but that's just - // an optimization. It's legal to notify regardless. - Assert.True(editContext.Validate()); - Assert.Equal(3, onValidationStateChangedCount); - } - - [Fact] - public void PerformsPerPropertyValidationOnFieldChange() - { - // Arrange - var model = new TestModel { IntFrom1To100 = 101 }; - var independentTopLevelModel = new object(); // To show we can validate things on any model, not just the top-level one - var editContext = new EditContext(independentTopLevelModel).AddDataAnnotationsValidation(); - var onValidationStateChangedCount = 0; - var requiredStringIdentifier = new FieldIdentifier(model, nameof(TestModel.RequiredString)); - var intFrom1To100Identifier = new FieldIdentifier(model, nameof(TestModel.IntFrom1To100)); - editContext.OnValidationStateChanged += (sender, eventArgs) => onValidationStateChangedCount++; - - // Act/Assert 1: Notify about RequiredString - // Only RequiredString gets validated, even though IntFrom1To100 also holds an invalid value - editContext.NotifyFieldChanged(requiredStringIdentifier); - Assert.Equal(1, onValidationStateChangedCount); - Assert.Equal(new[] { "RequiredString:required" }, editContext.GetValidationMessages()); - - // Act/Assert 2: Fix RequiredString, but only notify about IntFrom1To100 - // Only IntFrom1To100 gets validated; messages for RequiredString are left unchanged - model.RequiredString = "This string is very cool and very legal"; - editContext.NotifyFieldChanged(intFrom1To100Identifier); - Assert.Equal(2, onValidationStateChangedCount); - Assert.Equal(new string[] - { - "RequiredString:required", - "IntFrom1To100:range" - }, - editContext.GetValidationMessages()); - - // Act/Assert 3: Notify about RequiredString - editContext.NotifyFieldChanged(requiredStringIdentifier); - Assert.Equal(3, onValidationStateChangedCount); - Assert.Equal(new[] { "IntFrom1To100:range" }, editContext.GetValidationMessages()); - } - - [Theory] - [InlineData(nameof(TestModel.ThisWillNotBeValidatedBecauseItIsAField))] - [InlineData(nameof(TestModel.ThisWillNotBeValidatedBecauseItIsInternal))] - [InlineData("ThisWillNotBeValidatedBecauseItIsPrivate")] - [InlineData("This does not correspond to anything")] - [InlineData("")] - public void IgnoresFieldChangesThatDoNotCorrespondToAValidatableProperty(string fieldName) - { - // Arrange - var editContext = new EditContext(new TestModel()).AddDataAnnotationsValidation(); - var onValidationStateChangedCount = 0; - editContext.OnValidationStateChanged += (sender, eventArgs) => onValidationStateChangedCount++; - - // Act/Assert: Ignores field changes that don't correspond to a validatable property - editContext.NotifyFieldChanged(editContext.Field(fieldName)); - Assert.Equal(0, onValidationStateChangedCount); - - // Act/Assert: For sanity, observe that we would have validated if it was a validatable property - editContext.NotifyFieldChanged(editContext.Field(nameof(TestModel.RequiredString))); - Assert.Equal(1, onValidationStateChangedCount); - } - - class TestModel - { - [Required(ErrorMessage = "RequiredString:required")] public string RequiredString { get; set; } - - [Range(1, 100, ErrorMessage = "IntFrom1To100:range")] public int IntFrom1To100 { get; set; } - -#pragma warning disable 649 - [Required] public string ThisWillNotBeValidatedBecauseItIsAField; - [Required] string ThisWillNotBeValidatedBecauseItIsPrivate { get; set; } - [Required] internal string ThisWillNotBeValidatedBecauseItIsInternal { get; set; } -#pragma warning restore 649 - } - } -} diff --git a/src/Components/Forms/test/EditContextTest.cs b/src/Components/Forms/test/EditContextTest.cs deleted file mode 100644 index 5c8e7af36e..0000000000 --- a/src/Components/Forms/test/EditContextTest.cs +++ /dev/null @@ -1,240 +0,0 @@ -// 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.Linq; -using Xunit; - -namespace Microsoft.AspNetCore.Components.Forms -{ - public class EditContextTest - { - [Fact] - public void CannotUseNullModel() - { - var ex = Assert.Throws(() => new EditContext(null)); - Assert.Equal("model", ex.ParamName); - } - - [Fact] - public void CanGetModel() - { - var model = new object(); - var editContext = new EditContext(model); - Assert.Same(model, editContext.Model); - } - - [Fact] - public void CanConstructFieldIdentifiersForRootModel() - { - // Arrange/Act - var model = new object(); - var editContext = new EditContext(model); - var fieldIdentifier = editContext.Field("testFieldName"); - - // Assert - Assert.Same(model, fieldIdentifier.Model); - Assert.Equal("testFieldName", fieldIdentifier.FieldName); - } - - [Fact] - public void IsInitiallyUnmodified() - { - var editContext = new EditContext(new object()); - Assert.False(editContext.IsModified()); - } - - [Fact] - public void TracksFieldsAsModifiedWhenValueChanged() - { - // Arrange - var editContext = new EditContext(new object()); - var fieldOnThisModel1 = editContext.Field("field1"); - var fieldOnThisModel2 = editContext.Field("field2"); - var fieldOnOtherModel = new FieldIdentifier(new object(), "field on other model"); - - // Act - editContext.NotifyFieldChanged(fieldOnThisModel1); - editContext.NotifyFieldChanged(fieldOnOtherModel); - - // Assert - Assert.True(editContext.IsModified()); - Assert.True(editContext.IsModified(fieldOnThisModel1)); - Assert.False(editContext.IsModified(fieldOnThisModel2)); - Assert.True(editContext.IsModified(fieldOnOtherModel)); - } - - [Fact] - public void CanClearIndividualModifications() - { - // Arrange - var editContext = new EditContext(new object()); - var fieldThatWasModified = editContext.Field("field1"); - var fieldThatRemainsModified = editContext.Field("field2"); - var fieldThatWasNeverModified = editContext.Field("field that was never modified"); - editContext.NotifyFieldChanged(fieldThatWasModified); - editContext.NotifyFieldChanged(fieldThatRemainsModified); - - // Act - editContext.MarkAsUnmodified(fieldThatWasModified); - editContext.MarkAsUnmodified(fieldThatWasNeverModified); - - // Assert - Assert.True(editContext.IsModified()); - Assert.False(editContext.IsModified(fieldThatWasModified)); - Assert.True(editContext.IsModified(fieldThatRemainsModified)); - Assert.False(editContext.IsModified(fieldThatWasNeverModified)); - } - - [Fact] - public void CanClearAllModifications() - { - // Arrange - var editContext = new EditContext(new object()); - var field1 = editContext.Field("field1"); - var field2 = editContext.Field("field2"); - editContext.NotifyFieldChanged(field1); - editContext.NotifyFieldChanged(field2); - - // Act - editContext.MarkAsUnmodified(); - - // Assert - Assert.False(editContext.IsModified()); - Assert.False(editContext.IsModified(field1)); - Assert.False(editContext.IsModified(field2)); - } - - [Fact] - public void RaisesEventWhenFieldIsChanged() - { - // Arrange - var editContext = new EditContext(new object()); - var field1 = new FieldIdentifier(new object(), "fieldname"); // Shows it can be on a different model - var didReceiveNotification = false; - editContext.OnFieldChanged += (sender, eventArgs) => - { - Assert.Same(editContext, sender); - Assert.Equal(field1, eventArgs.FieldIdentifier); - didReceiveNotification = true; - }; - - // Act - editContext.NotifyFieldChanged(field1); - - // Assert - Assert.True(didReceiveNotification); - } - - [Fact] - public void CanEnumerateValidationMessagesAcrossAllStoresForSingleField() - { - // Arrange - var editContext = new EditContext(new object()); - var store1 = new ValidationMessageStore(editContext); - var store2 = new ValidationMessageStore(editContext); - var field = new FieldIdentifier(new object(), "field"); - var fieldWithNoState = new FieldIdentifier(new object(), "field with no state"); - store1.Add(field, "Store 1 message 1"); - store1.Add(field, "Store 1 message 2"); - store1.Add(new FieldIdentifier(new object(), "otherfield"), "Message for other field that should not appear in results"); - store2.Add(field, "Store 2 message 1"); - - // Act/Assert: Can pick out the messages for a field - Assert.Equal(new[] - { - "Store 1 message 1", - "Store 1 message 2", - "Store 2 message 1", - }, editContext.GetValidationMessages(field).OrderBy(x => x)); // Sort because the order isn't defined - - // Act/Assert: It's fine to ask for messages for a field with no associated state - Assert.Empty(editContext.GetValidationMessages(fieldWithNoState)); - - // Act/Assert: After clearing a single store, we only see the results from other stores - store1.Clear(field); - Assert.Equal(new[] { "Store 2 message 1", }, editContext.GetValidationMessages(field)); - } - - [Fact] - public void CanEnumerateValidationMessagesAcrossAllStoresForAllFields() - { - // Arrange - var editContext = new EditContext(new object()); - var store1 = new ValidationMessageStore(editContext); - var store2 = new ValidationMessageStore(editContext); - var field1 = new FieldIdentifier(new object(), "field1"); - var field2 = new FieldIdentifier(new object(), "field2"); - store1.Add(field1, "Store 1 field 1 message 1"); - store1.Add(field1, "Store 1 field 1 message 2"); - store1.Add(field2, "Store 1 field 2 message 1"); - store2.Add(field1, "Store 2 field 1 message 1"); - - // Act/Assert - Assert.Equal(new[] - { - "Store 1 field 1 message 1", - "Store 1 field 1 message 2", - "Store 1 field 2 message 1", - "Store 2 field 1 message 1", - }, editContext.GetValidationMessages().OrderBy(x => x)); // Sort because the order isn't defined - - // Act/Assert: After clearing a single store, we only see the results from other stores - store1.Clear(); - Assert.Equal(new[] { "Store 2 field 1 message 1", }, editContext.GetValidationMessages()); - } - - [Fact] - public void IsValidWithNoValidationMessages() - { - // Arrange - var editContext = new EditContext(new object()); - - // Act - var isValid = editContext.Validate(); - - // assert - Assert.True(isValid); - } - - [Fact] - public void IsInvalidWithValidationMessages() - { - // Arrange - var editContext = new EditContext(new object()); - var messages = new ValidationMessageStore(editContext); - messages.Add( - new FieldIdentifier(new object(), "some field"), - "Some message"); - - // Act - var isValid = editContext.Validate(); - - // assert - Assert.False(isValid); - } - - [Fact] - public void RequestsValidationWhenValidateIsCalled() - { - // Arrange - var editContext = new EditContext(new object()); - var messages = new ValidationMessageStore(editContext); - editContext.OnValidationRequested += (sender, eventArgs) => - { - Assert.Same(editContext, sender); - Assert.NotNull(eventArgs); - messages.Add( - new FieldIdentifier(new object(), "some field"), - "Some message"); - }; - - // Act - var isValid = editContext.Validate(); - - // assert - Assert.False(isValid); - Assert.Equal(new[] { "Some message" }, editContext.GetValidationMessages()); - } - } -} diff --git a/src/Components/Forms/test/FieldIdentifierTest.cs b/src/Components/Forms/test/FieldIdentifierTest.cs deleted file mode 100644 index f19751a45d..0000000000 --- a/src/Components/Forms/test/FieldIdentifierTest.cs +++ /dev/null @@ -1,198 +0,0 @@ -// 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.Collections.Generic; -using System.Linq.Expressions; -using Xunit; - -namespace Microsoft.AspNetCore.Components.Forms -{ - public class FieldIdentifierTest - { - [Fact] - public void CannotUseNullModel() - { - var ex = Assert.Throws(() => new FieldIdentifier(null, "somefield")); - Assert.Equal("model", ex.ParamName); - } - - [Fact] - public void CannotUseValueTypeModel() - { - var ex = Assert.Throws(() => new FieldIdentifier(DateTime.Now, "somefield")); - Assert.Equal("model", ex.ParamName); - Assert.StartsWith("The model must be a reference-typed object.", ex.Message); - } - - [Fact] - public void CannotUseNullFieldName() - { - var ex = Assert.Throws(() => new FieldIdentifier(new object(), null)); - Assert.Equal("fieldName", ex.ParamName); - } - - [Fact] - public void CanUseEmptyFieldName() - { - var fieldIdentifier = new FieldIdentifier(new object(), string.Empty); - Assert.Equal(string.Empty, fieldIdentifier.FieldName); - } - - [Fact] - public void CanGetModelAndFieldName() - { - // Arrange/Act - var model = new object(); - var fieldIdentifier = new FieldIdentifier(model, "someField"); - - // Assert - Assert.Same(model, fieldIdentifier.Model); - Assert.Equal("someField", fieldIdentifier.FieldName); - } - - [Fact] - public void DistinctModelsProduceDistinctHashCodesAndNonEquality() - { - // Arrange - var fieldIdentifier1 = new FieldIdentifier(new object(), "field"); - var fieldIdentifier2 = new FieldIdentifier(new object(), "field"); - - // Act/Assert - Assert.NotEqual(fieldIdentifier1.GetHashCode(), fieldIdentifier2.GetHashCode()); - Assert.False(fieldIdentifier1.Equals(fieldIdentifier2)); - } - - [Fact] - public void DistinctFieldNamesProduceDistinctHashCodesAndNonEquality() - { - // Arrange - var model = new object(); - var fieldIdentifier1 = new FieldIdentifier(model, "field1"); - var fieldIdentifier2 = new FieldIdentifier(model, "field2"); - - // Act/Assert - Assert.NotEqual(fieldIdentifier1.GetHashCode(), fieldIdentifier2.GetHashCode()); - Assert.False(fieldIdentifier1.Equals(fieldIdentifier2)); - } - - [Fact] - public void SameContentsProduceSameHashCodesAndEquality() - { - // Arrange - var model = new object(); - var fieldIdentifier1 = new FieldIdentifier(model, "field"); - var fieldIdentifier2 = new FieldIdentifier(model, "field"); - - // Act/Assert - Assert.Equal(fieldIdentifier1.GetHashCode(), fieldIdentifier2.GetHashCode()); - Assert.True(fieldIdentifier1.Equals(fieldIdentifier2)); - } - - [Fact] - public void FieldNamesAreCaseSensitive() - { - // Arrange - var model = new object(); - var fieldIdentifierLower = new FieldIdentifier(model, "field"); - var fieldIdentifierPascal = new FieldIdentifier(model, "Field"); - - // Act/Assert - Assert.Equal("field", fieldIdentifierLower.FieldName); - Assert.Equal("Field", fieldIdentifierPascal.FieldName); - Assert.NotEqual(fieldIdentifierLower.GetHashCode(), fieldIdentifierPascal.GetHashCode()); - Assert.False(fieldIdentifierLower.Equals(fieldIdentifierPascal)); - } - - [Fact] - public void CanCreateFromExpression_Property() - { - var model = new TestModel(); - var fieldIdentifier = FieldIdentifier.Create(() => model.StringProperty); - Assert.Same(model, fieldIdentifier.Model); - Assert.Equal(nameof(model.StringProperty), fieldIdentifier.FieldName); - } - - [Fact] - public void CannotCreateFromExpression_NonMember() - { - var ex = Assert.Throws(() => - FieldIdentifier.Create(() => new TestModel())); - Assert.Equal($"The provided expression contains a NewExpression which is not supported. {nameof(FieldIdentifier)} only supports simple member accessors (fields, properties) of an object.", ex.Message); - } - - [Fact] - public void CanCreateFromExpression_Field() - { - var model = new TestModel(); - var fieldIdentifier = FieldIdentifier.Create(() => model.StringField); - Assert.Same(model, fieldIdentifier.Model); - Assert.Equal(nameof(model.StringField), fieldIdentifier.FieldName); - } - - [Fact] - public void CanCreateFromExpression_WithCastToObject() - { - // This case is needed because, if a component is declared as receiving - // an Expression>, then any value types will be implicitly cast - var model = new TestModel(); - Expression> accessor = () => model.IntProperty; - var fieldIdentifier = FieldIdentifier.Create(accessor); - Assert.Same(model, fieldIdentifier.Model); - Assert.Equal(nameof(model.IntProperty), fieldIdentifier.FieldName); - } - - [Fact] - public void CanCreateFromExpression_MemberOfConstantExpression() - { - var fieldIdentifier = FieldIdentifier.Create(() => StringPropertyOnThisClass); - Assert.Same(this, fieldIdentifier.Model); - Assert.Equal(nameof(StringPropertyOnThisClass), fieldIdentifier.FieldName); - } - - [Fact] - public void CanCreateFromExpression_MemberOfChildObject() - { - var parentModel = new ParentModel { Child = new TestModel() }; - var fieldIdentifier = FieldIdentifier.Create(() => parentModel.Child.StringField); - Assert.Same(parentModel.Child, fieldIdentifier.Model); - Assert.Equal(nameof(TestModel.StringField), fieldIdentifier.FieldName); - } - - [Fact] - public void CanCreateFromExpression_MemberOfIndexedCollectionEntry() - { - var models = new List() { null, new TestModel() }; - var fieldIdentifier = FieldIdentifier.Create(() => models[1].StringField); - Assert.Same(models[1], fieldIdentifier.Model); - Assert.Equal(nameof(TestModel.StringField), fieldIdentifier.FieldName); - } - - [Fact] - public void CanCreateFromExpression_MemberOfObjectWithCast() - { - var model = new TestModel(); - var fieldIdentifier = FieldIdentifier.Create(() => ((TestModel)(object)model).StringField); - Assert.Same(model, fieldIdentifier.Model); - Assert.Equal(nameof(TestModel.StringField), fieldIdentifier.FieldName); - } - - string StringPropertyOnThisClass { get; set; } - - class TestModel - { - public string StringProperty { get; set; } - - public int IntProperty { get; set; } - -#pragma warning disable 649 - public string StringField; -#pragma warning restore 649 - } - - class ParentModel - { - public TestModel Child { get; set; } - } - } -} diff --git a/src/Components/Forms/test/Microsoft.AspNetCore.Components.Forms.Tests.csproj b/src/Components/Forms/test/Microsoft.AspNetCore.Components.Forms.Tests.csproj deleted file mode 100644 index 6c611379a5..0000000000 --- a/src/Components/Forms/test/Microsoft.AspNetCore.Components.Forms.Tests.csproj +++ /dev/null @@ -1,17 +0,0 @@ - - - - $(DefaultNetCoreTargetFramework) - Microsoft.AspNetCore.Components.Forms - - - - - - - - - - - - diff --git a/src/Components/Forms/test/ValidationMessageStoreTest.cs b/src/Components/Forms/test/ValidationMessageStoreTest.cs deleted file mode 100644 index 5264e254bd..0000000000 --- a/src/Components/Forms/test/ValidationMessageStoreTest.cs +++ /dev/null @@ -1,96 +0,0 @@ -// 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 Xunit; - -namespace Microsoft.AspNetCore.Components.Forms -{ - public class ValidationMessageStoreTest - { - [Fact] - public void CannotUseNullEditContext() - { - var ex = Assert.Throws(() => new ValidationMessageStore(null)); - Assert.Equal("editContext", ex.ParamName); - } - - [Fact] - public void CanCreateForEditContext() - { - new ValidationMessageStore(new EditContext(new object())); - } - - [Fact] - public void CanAddMessages() - { - // Arrange - var messages = new ValidationMessageStore(new EditContext(new object())); - var field1 = new FieldIdentifier(new object(), "field1"); - var field2 = new FieldIdentifier(new object(), "field2"); - var field3 = new FieldIdentifier(new object(), "field3"); - - // Act - messages.Add(field1, "Field 1 message 1"); - messages.Add(field1, "Field 1 message 2"); - messages.Add(field2, "Field 2 message 1"); - - // Assert - Assert.Equal(new[] { "Field 1 message 1", "Field 1 message 2" }, messages[field1]); - Assert.Equal(new[] { "Field 2 message 1" }, messages[field2]); - Assert.Empty(messages[field3]); - } - - [Fact] - public void CanAddMessagesMultiple() - { - // Arrange - var messages = new ValidationMessageStore(new EditContext(new object())); - var field1 = new FieldIdentifier(new object(), "field1"); - var entries = new[] { "A", "B", "C" }; - - // Act - messages.Add(field1, entries); - - // Assert - Assert.Equal(entries, messages[field1]); - } - - [Fact] - public void CanClearMessagesForSingleField() - { - // Arrange - var messages = new ValidationMessageStore(new EditContext(new object())); - var field1 = new FieldIdentifier(new object(), "field1"); - var field2 = new FieldIdentifier(new object(), "field2"); - messages.Add(field1, "Field 1 message 1"); - messages.Add(field1, "Field 1 message 2"); - messages.Add(field2, "Field 2 message 1"); - - // Act - messages.Clear(field1); - - // Assert - Assert.Empty(messages[field1]); - Assert.Equal(new[] { "Field 2 message 1" }, messages[field2]); - } - - [Fact] - public void CanClearMessagesForAllFields() - { - // Arrange - var messages = new ValidationMessageStore(new EditContext(new object())); - var field1 = new FieldIdentifier(new object(), "field1"); - var field2 = new FieldIdentifier(new object(), "field2"); - messages.Add(field1, "Field 1 message 1"); - messages.Add(field2, "Field 2 message 1"); - - // Act - messages.Clear(); - - // Assert - Assert.Empty(messages[field1]); - Assert.Empty(messages[field2]); - } - } -} diff --git a/src/Components/Ignitor/src/BlazorClient.cs b/src/Components/Ignitor/src/BlazorClient.cs deleted file mode 100644 index 46637eb3bb..0000000000 --- a/src/Components/Ignitor/src/BlazorClient.cs +++ /dev/null @@ -1,540 +0,0 @@ -// 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.Linq; -using System.Net.Http; -using System.Text.Json; -using System.Text.RegularExpressions; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.AspNetCore.SignalR.Client; -using Microsoft.AspNetCore.SignalR.Protocol; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.DependencyInjection.Extensions; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Logging.Abstractions; - -#nullable enable -namespace Ignitor -{ - public class BlazorClient : IAsyncDisposable - { - private const string MarkerPattern = ".*?.*?"; - private HubConnection? _hubConnection; - - public BlazorClient() - { - CancellationTokenSource = new CancellationTokenSource(); - CancellationToken = CancellationTokenSource.Token; - TaskCompletionSource = new TaskCompletionSource(); - - CancellationTokenSource.Token.Register(() => - { - TaskCompletionSource.TrySetCanceled(); - }); - } - - public TimeSpan? DefaultConnectionTimeout { get; set; } = TimeSpan.FromSeconds(20); - public TimeSpan? DefaultOperationTimeout { get; set; } = TimeSpan.FromMilliseconds(500); - - /// - /// Gets or sets a value that determines whether the client will capture data such - /// as render batches, interop calls, and errors for later inspection. - /// - public bool CaptureOperations { get; set; } - - /// - /// Gets the collections of operation results that are captured when - /// is true. - /// - public Operations Operations { get; } = new Operations(); - - public Func? FormatError { get; set; } - - private CancellationTokenSource CancellationTokenSource { get; } - - private CancellationToken CancellationToken { get; } - - private TaskCompletionSource TaskCompletionSource { get; } - - private CancellableOperation? NextAttachComponentReceived { get; set; } - - private CancellableOperation? NextBatchReceived { get; set; } - - private CancellableOperation? NextErrorReceived { get; set; } - - private CancellableOperation? NextDisconnect { get; set; } - - private CancellableOperation? NextJSInteropReceived { get; set; } - - private CancellableOperation? NextDotNetInteropCompletionReceived { get; set; } - - public ILoggerProvider LoggerProvider { get; set; } = NullLoggerProvider.Instance; - - public bool ConfirmRenderBatch { get; set; } = true; - - public event Action? JSInterop; - - public event Action? RenderBatchReceived; - - public event Action? DotNetInteropCompletion; - - public event Action? OnCircuitError; - - public string? CircuitId { get; private set; } - - public ElementHive Hive { get; } = new ElementHive(); - - public bool ImplicitWait => DefaultOperationTimeout != null; - - public HubConnection HubConnection => _hubConnection ?? throw new InvalidOperationException("HubConnection has not been initialized."); - - public Task PrepareForNextBatch(TimeSpan? timeout) - { - if (NextBatchReceived != null && !NextBatchReceived.Disposed) - { - throw new InvalidOperationException("Invalid state previous task not completed"); - } - - NextBatchReceived = new CancellableOperation(timeout, CancellationToken); - return NextBatchReceived.Completion.Task; - } - - public Task PrepareForNextJSInterop(TimeSpan? timeout) - { - if (NextJSInteropReceived != null && !NextJSInteropReceived.Disposed) - { - throw new InvalidOperationException("Invalid state previous task not completed"); - } - - NextJSInteropReceived = new CancellableOperation(timeout, CancellationToken); - - return NextJSInteropReceived.Completion.Task; - } - - public Task PrepareForNextDotNetInterop(TimeSpan? timeout) - { - if (NextDotNetInteropCompletionReceived != null && !NextDotNetInteropCompletionReceived.Disposed) - { - throw new InvalidOperationException("Invalid state previous task not completed"); - } - - NextDotNetInteropCompletionReceived = new CancellableOperation(timeout, CancellationToken); - - return NextDotNetInteropCompletionReceived.Completion.Task; - } - - public Task PrepareForNextCircuitError(TimeSpan? timeout) - { - if (NextErrorReceived != null && !NextErrorReceived.Disposed) - { - throw new InvalidOperationException("Invalid state previous task not completed"); - } - - NextErrorReceived = new CancellableOperation(timeout, CancellationToken); - - return NextErrorReceived.Completion.Task; - } - - public Task PrepareForNextDisconnect(TimeSpan? timeout) - { - if (NextDisconnect != null && !NextDisconnect.Disposed) - { - throw new InvalidOperationException("Invalid state previous task not completed"); - } - - NextDisconnect = new CancellableOperation(timeout, CancellationToken); - - return NextDisconnect.Completion.Task; - } - - public Task ClickAsync(string elementId, bool expectRenderBatch = true) - { - if (!Hive.TryFindElementById(elementId, out var elementNode)) - { - throw new InvalidOperationException($"Could not find element with id {elementId}."); - } - if (expectRenderBatch) - { - return ExpectRenderBatch(() => elementNode.ClickAsync(HubConnection)); - } - else - { - return elementNode.ClickAsync(HubConnection); - } - } - - public Task SelectAsync(string elementId, string value) - { - if (!Hive.TryFindElementById(elementId, out var elementNode)) - { - throw new InvalidOperationException($"Could not find element with id {elementId}."); - } - - return ExpectRenderBatch(() => elementNode.SelectAsync(HubConnection, value)); - } - - public async Task ExpectRenderBatch(Func action, TimeSpan? timeout = null) - { - var task = WaitForRenderBatch(timeout); - await action(); - return await task; - } - - public async Task ExpectJSInterop(Func action, TimeSpan? timeout = null) - { - var task = WaitForJSInterop(timeout); - await action(); - return await task; - } - - public async Task ExpectDotNetInterop(Func action, TimeSpan? timeout = null) - { - var task = WaitForDotNetInterop(timeout); - await action(); - return await task; - } - - public async Task ExpectCircuitError(Func action, TimeSpan? timeout = null) - { - var task = WaitForCircuitError(timeout); - await action(); - return await task; - } - - public async Task ExpectDisconnect(Func action, TimeSpan? timeout = null) - { - var task = WaitForDisconnect(timeout); - await action(); - return await task; - } - - public async Task<(string? error, Exception? exception)> ExpectCircuitErrorAndDisconnect(Func action, TimeSpan? timeout = null) - { - string? error = default; - - // NOTE: timeout is used for each operation individually. - var exception = await ExpectDisconnect(async () => - { - error = await ExpectCircuitError(action, timeout); - }, timeout); - - return (error, exception); - } - - private async Task WaitForRenderBatch(TimeSpan? timeout = null) - { - if (ImplicitWait) - { - if (DefaultOperationTimeout == null && timeout == null) - { - throw new InvalidOperationException("Implicit wait without DefaultLatencyTimeout is not allowed."); - } - - try - { - return await PrepareForNextBatch(timeout ?? DefaultOperationTimeout); - } - catch (TimeoutException) when (FormatError != null) - { - throw FormatError("Timed out while waiting for batch."); - } - } - - return null; - } - - private async Task WaitForJSInterop(TimeSpan? timeout = null) - { - if (ImplicitWait) - { - if (DefaultOperationTimeout == null && timeout == null) - { - throw new InvalidOperationException("Implicit wait without DefaultLatencyTimeout is not allowed."); - } - - try - { - return await PrepareForNextJSInterop(timeout ?? DefaultOperationTimeout); - } - catch (TimeoutException) when (FormatError != null) - { - throw FormatError("Timed out while waiting for JS Interop."); - } - } - - return null; - } - - private async Task WaitForDotNetInterop(TimeSpan? timeout = null) - { - if (ImplicitWait) - { - if (DefaultOperationTimeout == null && timeout == null) - { - throw new InvalidOperationException("Implicit wait without DefaultLatencyTimeout is not allowed."); - } - - try - { - return await PrepareForNextDotNetInterop(timeout ?? DefaultOperationTimeout); - } - catch (TimeoutException) when (FormatError != null) - { - throw FormatError("Timed out while waiting for .NET interop."); - } - } - - return null; - } - - private async Task WaitForCircuitError(TimeSpan? timeout = null) - { - if (ImplicitWait) - { - if (DefaultOperationTimeout == null && timeout == null) - { - throw new InvalidOperationException("Implicit wait without DefaultLatencyTimeout is not allowed."); - } - - try - { - return await PrepareForNextCircuitError(timeout ?? DefaultOperationTimeout); - } - catch (TimeoutException) when (FormatError != null) - { - throw FormatError("Timed out while waiting for circuit error."); - } - } - - return null; - } - - private async Task WaitForDisconnect(TimeSpan? timeout = null) - { - if (ImplicitWait) - { - if (DefaultOperationTimeout == null && timeout == null) - { - throw new InvalidOperationException("Implicit wait without DefaultLatencyTimeout is not allowed."); - } - - try - { - return await PrepareForNextDisconnect(timeout ?? DefaultOperationTimeout); - } - catch (TimeoutException) when (FormatError != null) - { - throw FormatError("Timed out while waiting for disconnect."); - } - } - - return null; - } - - public async Task ConnectAsync(Uri uri, bool connectAutomatically = true) - { - var builder = new HubConnectionBuilder(); - builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton()); - builder.WithUrl(GetHubUrl(uri)); - builder.ConfigureLogging(l => - { - l.SetMinimumLevel(LogLevel.Trace); - if (LoggerProvider != null) - { - l.AddProvider(LoggerProvider); - } - }); - - _hubConnection = builder.Build(); - - HubConnection.On("JS.AttachComponent", OnAttachComponent); - HubConnection.On("JS.BeginInvokeJS", OnBeginInvokeJS); - HubConnection.On("JS.EndInvokeDotNet", OnEndInvokeDotNet); - HubConnection.On("JS.RenderBatch", OnRenderBatch); - HubConnection.On("JS.Error", OnError); - HubConnection.Closed += OnClosedAsync; - - await HubConnection.StartAsync(CancellationToken); - - if (!connectAutomatically) - { - return true; - } - - var descriptors = await GetPrerenderDescriptors(uri); - await ExpectRenderBatch( - async () => CircuitId = await HubConnection.InvokeAsync("StartCircuit", uri, uri, descriptors, CancellationToken), - DefaultConnectionTimeout); - return CircuitId != null; - } - - private void OnEndInvokeDotNet(string message) - { - Operations?.DotNetCompletions.Enqueue(message); - DotNetInteropCompletion?.Invoke(message); - - NextDotNetInteropCompletionReceived?.Completion?.TrySetResult(null); - } - - private void OnAttachComponent(int componentId, string domSelector) - { - var call = new CapturedAttachComponentCall(componentId, domSelector); - Operations?.AttachComponent.Enqueue(call); - - NextAttachComponentReceived?.Completion?.TrySetResult(call); - } - - private void OnBeginInvokeJS(int asyncHandle, string identifier, string argsJson) - { - var call = new CapturedJSInteropCall(asyncHandle, identifier, argsJson); - Operations?.JSInteropCalls.Enqueue(call); - JSInterop?.Invoke(call); - - NextJSInteropReceived?.Completion?.TrySetResult(null); - } - - private void OnRenderBatch(int id, byte[] data) - { - var capturedBatch = new CapturedRenderBatch(id, data); - - Operations?.Batches.Enqueue(capturedBatch); - RenderBatchReceived?.Invoke(capturedBatch); - - var batch = RenderBatchReader.Read(data); - - Hive.Update(batch); - - if (ConfirmRenderBatch) - { - _ = ConfirmBatch(id); - } - - NextBatchReceived?.Completion?.TrySetResult(null); - } - - public Task ConfirmBatch(int batchId, string? error = null) - { - return HubConnection.InvokeAsync("OnRenderCompleted", batchId, error, CancellationToken); - } - - private void OnError(string error) - { - Operations?.Errors.Enqueue(error); - OnCircuitError?.Invoke(error); - - // If we get an error, forcibly terminate anything else we're waiting for. These - // tests should only encounter errors in specific situations, and this ensures that - // we fail with a good message. - var exception = FormatError?.Invoke(error) ?? new Exception(error); - NextBatchReceived?.Completion?.TrySetException(exception); - NextDotNetInteropCompletionReceived?.Completion.TrySetException(exception); - NextJSInteropReceived?.Completion.TrySetException(exception); - NextAttachComponentReceived?.Completion?.TrySetException(exception); - NextErrorReceived?.Completion?.TrySetResult(null); - } - - private Task OnClosedAsync(Exception ex) - { - NextDisconnect?.Completion?.TrySetResult(null); - - if (ex == null) - { - TaskCompletionSource.TrySetResult(null); - } - else - { - TaskCompletionSource.TrySetException(ex); - } - - return Task.CompletedTask; - } - - private Uri GetHubUrl(Uri uri) - { - if (uri.Segments.Length == 1) - { - return new Uri(uri, "_blazor"); - } - else - { - var builder = new UriBuilder(uri); - builder.Path += builder.Path.EndsWith("/") ? "_blazor" : "/_blazor"; - return builder.Uri; - } - } - - public async Task InvokeDotNetMethod(object callId, string assemblyName, string methodIdentifier, object dotNetObjectId, string argsJson) - { - await ExpectDotNetInterop(() => HubConnection.InvokeAsync( - "BeginInvokeDotNetFromJS", - callId?.ToString(), - assemblyName, - methodIdentifier, - dotNetObjectId ?? 0, - argsJson, - CancellationToken)); - } - - public async Task GetPrerenderDescriptors(Uri uri) - { - var httpClient = new HttpClient(); - httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Cookie", "__blazor_execution_mode=server"); - var response = await httpClient.GetAsync(uri); - response.EnsureSuccessStatusCode(); - var content = await response.Content.ReadAsStringAsync(); - - var match = ReadMarkers(content); - return $"[{string.Join(", ", match)}]"; - } - - public void Cancel() - { - if (!CancellationTokenSource.IsCancellationRequested) - { - CancellationTokenSource.Cancel(); - CancellationTokenSource.Dispose(); - } - } - - public ElementNode FindElementById(string id) - { - if (!Hive.TryFindElementById(id, out var element)) - { - throw new InvalidOperationException($"Element with id '{id}' was not found."); - } - - return element; - } - - private string[] ReadMarkers(string content) - { - content = content.Replace("\r\n", "").Replace("\n", ""); - var matches = Regex.Matches(content, MarkerPattern); - var markers = matches.Select(s => (value: s.Groups[1].Value, parsed: JsonDocument.Parse(s.Groups[1].Value))) - .Where(s => - { - return s.parsed.RootElement.TryGetProperty("type", out var markerType) && - markerType.ValueKind != JsonValueKind.Undefined && - markerType.GetString() == "server"; - }) - .OrderBy(p => p.parsed.RootElement.GetProperty("sequence").GetInt32()) - .Select(p => p.value) - .ToArray(); - - return markers; - } - - public async ValueTask DisposeAsync() - { - Cancel(); - if (HubConnection != null) - { - await HubConnection.DisposeAsync(); - } - } - } -} - -#nullable restore diff --git a/src/Components/Ignitor/src/CancellableOperation.cs b/src/Components/Ignitor/src/CancellableOperation.cs deleted file mode 100644 index 6e1f217d19..0000000000 --- a/src/Components/Ignitor/src/CancellableOperation.cs +++ /dev/null @@ -1,78 +0,0 @@ -// 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; - -#nullable enable -namespace Ignitor -{ - internal class CancellableOperation - { - public CancellableOperation(TimeSpan? timeout, CancellationToken cancellationToken) - { - Timeout = timeout; - - Completion = new TaskCompletionSource(TaskContinuationOptions.RunContinuationsAsynchronously); - Completion.Task.ContinueWith( - (task, state) => - { - var operation = (CancellableOperation)state!; - operation.Dispose(); - }, - this, - TaskContinuationOptions.ExecuteSynchronously); // We need to execute synchronously to clean-up before anything else continues - - - Cancellation = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); - - if (Timeout != null && Timeout != System.Threading.Timeout.InfiniteTimeSpan && Timeout != TimeSpan.MaxValue) - { - Cancellation.CancelAfter(Timeout.Value); - } - - CancellationRegistration = Cancellation.Token.Register( - (self) => - { - var operation = (CancellableOperation)self!; - - if (cancellationToken.IsCancellationRequested) - { - // The operation was externally canceled before it timed out. - Dispose(); - return; - } - - operation.Completion.TrySetException(new TimeoutException($"The operation timed out after {Timeout}.")); - operation.Cancellation?.Dispose(); - operation.CancellationRegistration.Dispose(); - }, - this); - } - - public TimeSpan? Timeout { get; } - - public TaskCompletionSource Completion { get; } - - public CancellationTokenSource Cancellation { get; } - - public CancellationTokenRegistration CancellationRegistration { get; } - - public bool Disposed { get; private set; } - - private void Dispose() - { - if (Disposed) - { - return; - } - - Disposed = true; - Completion.TrySetCanceled(Cancellation.Token); - Cancellation.Dispose(); - CancellationRegistration.Dispose(); - } - } -} -#nullable restore diff --git a/src/Components/Ignitor/src/CapturedAttachComponentCall.cs b/src/Components/Ignitor/src/CapturedAttachComponentCall.cs deleted file mode 100644 index b3897c9579..0000000000 --- a/src/Components/Ignitor/src/CapturedAttachComponentCall.cs +++ /dev/null @@ -1,17 +0,0 @@ -// 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. - -namespace Ignitor -{ - public readonly struct CapturedAttachComponentCall - { - public CapturedAttachComponentCall(int componentId, string selector) - { - ComponentId = componentId; - Selector = selector; - } - - public int ComponentId { get; } - public string Selector { get; } - } -} diff --git a/src/Components/Ignitor/src/CapturedJSInteropCall.cs b/src/Components/Ignitor/src/CapturedJSInteropCall.cs deleted file mode 100644 index 4af491a58a..0000000000 --- a/src/Components/Ignitor/src/CapturedJSInteropCall.cs +++ /dev/null @@ -1,19 +0,0 @@ -// 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. - -namespace Ignitor -{ - public class CapturedJSInteropCall - { - public CapturedJSInteropCall(int asyncHandle, string identifier, string argsJson) - { - AsyncHandle = asyncHandle; - Identifier = identifier; - ArgsJson = argsJson; - } - - public int AsyncHandle { get; } - public string Identifier { get; } - public string ArgsJson { get; } - } -} diff --git a/src/Components/Ignitor/src/CapturedRenderBatch.cs b/src/Components/Ignitor/src/CapturedRenderBatch.cs deleted file mode 100644 index df2de87e9f..0000000000 --- a/src/Components/Ignitor/src/CapturedRenderBatch.cs +++ /dev/null @@ -1,17 +0,0 @@ -// 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. - -namespace Ignitor -{ - public class CapturedRenderBatch - { - public CapturedRenderBatch(int id, byte[] data) - { - Id = id; - Data = data; - } - - public int Id { get; } - public byte[] Data { get; } - } -} diff --git a/src/Components/Ignitor/src/CommentNode.cs b/src/Components/Ignitor/src/CommentNode.cs deleted file mode 100644 index 9f273e5d61..0000000000 --- a/src/Components/Ignitor/src/CommentNode.cs +++ /dev/null @@ -1,9 +0,0 @@ -// 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. - -namespace Ignitor -{ - internal class LogicalContainerNode : ContainerNode - { - } -} diff --git a/src/Components/Ignitor/src/ComponentNode.cs b/src/Components/Ignitor/src/ComponentNode.cs deleted file mode 100644 index a6829bb307..0000000000 --- a/src/Components/Ignitor/src/ComponentNode.cs +++ /dev/null @@ -1,15 +0,0 @@ -// 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. - -namespace Ignitor -{ - public class ComponentNode : ContainerNode - { - private readonly int _componentId; - - public ComponentNode(int componentId) - { - _componentId = componentId; - } - } -} diff --git a/src/Components/Ignitor/src/ComponentState.cs b/src/Components/Ignitor/src/ComponentState.cs deleted file mode 100644 index 28683bee11..0000000000 --- a/src/Components/Ignitor/src/ComponentState.cs +++ /dev/null @@ -1,18 +0,0 @@ -// 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. - -namespace Ignitor -{ -#nullable enable - public class ComponentState - { - public ComponentState(int componentId) - { - ComponentId = componentId; - } - - public int ComponentId { get; } - public IComponent? Component { get; } - } -#nullable restore -} diff --git a/src/Components/Ignitor/src/ContainerNode.cs b/src/Components/Ignitor/src/ContainerNode.cs deleted file mode 100644 index 24ee50b458..0000000000 --- a/src/Components/Ignitor/src/ContainerNode.cs +++ /dev/null @@ -1,86 +0,0 @@ -// 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.Collections.Generic; - -#nullable enable -namespace Ignitor -{ - public abstract class ContainerNode : Node - { - private readonly List _children; - - protected ContainerNode() - { - _children = new List(); - } - - public IReadOnlyList Children => _children; - - public void InsertLogicalChild(Node child, int childIndex) - { - if (child is LogicalContainerNode comment && comment.Children.Count > 0) - { - // There's nothing to stop us implementing support for this scenario, and it's not difficult - // (after inserting 'child' itself, also iterate through its logical children and physically - // put them as following-siblings in the DOM). However there's no scenario that requires it - // presently, so if we did implement it there'd be no good way to have tests for it. - throw new Exception("Not implemented: inserting non-empty logical container"); - } - - if (child.Parent != null) - { - // Likewise, we could easily support this scenario too (in this 'if' block, just splice - // out 'child' from the logical children array of its previous logical parent by using - // Array.prototype.indexOf to determine its previous sibling index). - // But again, since there's not currently any scenario that would use it, we would not - // have any test coverage for such an implementation. - throw new NotSupportedException("Not implemented: moving existing logical children"); - } - - if (childIndex < Children.Count) - { - // Insert - _children.Insert(childIndex, child); - } - else - { - // Append - _children.Add(child); - } - - child.Parent = this; - } - - public ContainerNode CreateAndInsertContainer(int childIndex) - { - var containerElement = new LogicalContainerNode(); - InsertLogicalChild(containerElement, childIndex); - return containerElement; - } - - public ComponentNode CreateAndInsertComponent(int componentId, int childIndex) - { - var componentElement = new ComponentNode(componentId); - InsertLogicalChild(componentElement, childIndex); - return componentElement; - } - - public void RemoveLogicalChild(int childIndex) - { - var childToRemove = Children[childIndex]; - _children.RemoveAt(childIndex); - - // If it's a logical container, also remove its descendants - if (childToRemove is LogicalContainerNode container) - { - while (container.Children.Count > 0) - { - container.RemoveLogicalChild(0); - } - } - } - } -} -#nullable restore diff --git a/src/Components/Ignitor/src/ElementHive.cs b/src/Components/Ignitor/src/ElementHive.cs deleted file mode 100644 index 3bb37c38ce..0000000000 --- a/src/Components/Ignitor/src/ElementHive.cs +++ /dev/null @@ -1,475 +0,0 @@ -// 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.Collections.Generic; -using System.Diagnostics.CodeAnalysis; - -#nullable enable -namespace Ignitor -{ - public class ElementHive - { - private const string SelectValuePropname = "_blazorSelectValue"; - - public Dictionary Components { get; } = new Dictionary(); - - public string SerializedValue => NodeSerializer.Serialize(this); - - public void Update(RenderBatch batch) - { - for (var i = 0; i < batch.UpdatedComponents.Count; i++) - { - var diff = batch.UpdatedComponents.Array[i]; - var componentId = diff.ComponentId; - var edits = diff.Edits; - UpdateComponent(batch, componentId, edits); - } - - for (var i = 0; i < batch.DisposedComponentIDs.Count; i++) - { - DisposeComponent(batch.DisposedComponentIDs.Array[i]); - } - - for (var i = 0; i < batch.DisposedEventHandlerIDs.Count; i++) - { - DisposeEventHandler(batch.DisposedEventHandlerIDs.Array[i]); - } - } - - public bool TryFindElementById(string id, [NotNullWhen(true)] out ElementNode? element) - { - foreach (var kvp in Components) - { - var component = kvp.Value; - if (TryGetElementFromChildren(component, out element)) - { - return true; - } - } - - element = null; - return false; - - bool TryGetElementFromChildren(Node node, out ElementNode? foundNode) - { - if (node is ElementNode elementNode && - elementNode.Attributes.TryGetValue("id", out var elementId) && - elementId?.ToString() == id) - { - foundNode = elementNode; - return true; - } - - if (node is ContainerNode containerNode) - { - for (var i = 0; i < containerNode.Children.Count; i++) - { - if (TryGetElementFromChildren(containerNode.Children[i], out foundNode)) - { - return true; - } - } - } - - foundNode = null; - return false; - } - } - - private void UpdateComponent(RenderBatch batch, int componentId, ArrayBuilderSegment edits) - { - if (!Components.TryGetValue(componentId, out var component)) - { - component = new ComponentNode(componentId); - Components.Add(componentId, component); - - } - - ApplyEdits(batch, component, 0, edits); - } - - private void DisposeComponent(int componentId) - { - - } - - private void DisposeEventHandler(ulong eventHandlerId) - { - - } - - private void ApplyEdits(RenderBatch batch, ContainerNode parent, int childIndex, ArrayBuilderSegment edits) - { - var currentDepth = 0; - var childIndexAtCurrentDepth = childIndex; - var permutations = new List(); - - for (var editIndex = edits.Offset; editIndex < edits.Offset + edits.Count; editIndex++) - { - var edit = edits.Array[editIndex]; - switch (edit.Type) - { - case RenderTreeEditType.PrependFrame: - { - var frame = batch.ReferenceFrames.Array[edit.ReferenceFrameIndex]; - var siblingIndex = edit.SiblingIndex; - InsertFrame(batch, parent, childIndexAtCurrentDepth + siblingIndex, batch.ReferenceFrames.Array, frame, edit.ReferenceFrameIndex); - break; - } - - case RenderTreeEditType.RemoveFrame: - { - var siblingIndex = edit.SiblingIndex; - parent.RemoveLogicalChild(childIndexAtCurrentDepth + siblingIndex); - break; - } - - case RenderTreeEditType.SetAttribute: - { - var frame = batch.ReferenceFrames.Array[edit.ReferenceFrameIndex]; - var siblingIndex = edit.SiblingIndex; - var node = parent.Children[childIndexAtCurrentDepth + siblingIndex]; - if (node is ElementNode element) - { - ApplyAttribute(batch, element, frame); - } - else - { - throw new Exception("Cannot set attribute on non-element child"); - } - break; - } - - case RenderTreeEditType.RemoveAttribute: - { - // Note that we don't have to dispose the info we track about event handlers here, because the - // disposed event handler IDs are delivered separately (in the 'disposedEventHandlerIds' array) - var siblingIndex = edit.SiblingIndex; - var node = parent.Children[childIndexAtCurrentDepth + siblingIndex]; - if (node is ElementNode element) - { - var attributeName = edit.RemovedAttributeName; - - // First try to remove any special property we use for this attribute - if (!TryApplySpecialProperty(batch, element, attributeName, default)) - { - // If that's not applicable, it's a regular DOM attribute so remove that - element.RemoveAttribute(attributeName); - } - } - else - { - throw new Exception("Cannot remove attribute from non-element child"); - } - break; - } - - case RenderTreeEditType.UpdateText: - { - var frame = batch.ReferenceFrames.Array[edit.ReferenceFrameIndex]; - var siblingIndex = edit.SiblingIndex; - var node = parent.Children[childIndexAtCurrentDepth + siblingIndex]; - if (node is TextNode textNode) - { - textNode.TextContent = frame.TextContent; - } - else - { - throw new Exception("Cannot set text content on non-text child"); - } - break; - } - - - case RenderTreeEditType.UpdateMarkup: - { - var frame = batch.ReferenceFrames.Array[edit.ReferenceFrameIndex]; - var siblingIndex = edit.SiblingIndex; - parent.RemoveLogicalChild(childIndexAtCurrentDepth + siblingIndex); - InsertMarkup(parent, childIndexAtCurrentDepth + siblingIndex, frame); - break; - } - - case RenderTreeEditType.StepIn: - { - var siblingIndex = edit.SiblingIndex; - parent = (ContainerNode)parent.Children[childIndexAtCurrentDepth + siblingIndex]; - currentDepth++; - childIndexAtCurrentDepth = 0; - break; - } - - case RenderTreeEditType.StepOut: - { - parent = parent.Parent ?? throw new InvalidOperationException($"Cannot step out of {parent}"); - currentDepth--; - childIndexAtCurrentDepth = currentDepth == 0 ? childIndex : 0; // The childIndex is only ever nonzero at zero depth - break; - } - - case RenderTreeEditType.PermutationListEntry: - { - permutations.Add(new PermutationListEntry(childIndexAtCurrentDepth + edit.SiblingIndex, childIndexAtCurrentDepth + edit.MoveToSiblingIndex)); - break; - } - - case RenderTreeEditType.PermutationListEnd: - { - throw new NotSupportedException(); - //permuteLogicalChildren(parent, permutations!); - //permutations.Clear(); - //break; - } - - default: - { - throw new Exception($"Unknown edit type: '{edit.Type}'"); - } - } - } - } - - private int InsertFrame(RenderBatch batch, ContainerNode parent, int childIndex, ArraySegment frames, RenderTreeFrame frame, int frameIndex) - { - switch (frame.FrameType) - { - case RenderTreeFrameType.Element: - { - InsertElement(batch, parent, childIndex, frames, frame, frameIndex); - return 1; - } - - case RenderTreeFrameType.Text: - { - InsertText(parent, childIndex, frame); - return 1; - } - - case RenderTreeFrameType.Attribute: - { - throw new Exception("Attribute frames should only be present as leading children of element frames."); - } - - case RenderTreeFrameType.Component: - { - InsertComponent(parent, childIndex, frame); - return 1; - } - - case RenderTreeFrameType.Region: - { - return InsertFrameRange(batch, parent, childIndex, frames, frameIndex + 1, frameIndex + CountDescendantFrames(frame)); - } - - case RenderTreeFrameType.ElementReferenceCapture: - { - // No action for reference captures. - break; - } - - case RenderTreeFrameType.Markup: - { - InsertMarkup(parent, childIndex, frame); - return 1; - } - - } - - throw new Exception($"Unknown frame type: {frame.FrameType}"); - } - - private void InsertText(ContainerNode parent, int childIndex, RenderTreeFrame frame) - { - var textContent = frame.TextContent; - var newTextNode = new TextNode(textContent); - parent.InsertLogicalChild(newTextNode, childIndex); - } - - private void InsertComponent(ContainerNode parent, int childIndex, RenderTreeFrame frame) - { - // All we have to do is associate the child component ID with its location. We don't actually - // do any rendering here, because the diff for the child will appear later in the render batch. - var childComponentId = frame.ComponentId; - var containerElement = parent.CreateAndInsertComponent(childComponentId, childIndex); - - Components[childComponentId] = containerElement; - } - - private int InsertFrameRange(RenderBatch batch, ContainerNode parent, int childIndex, ArraySegment frames, int startIndex, int endIndexExcl) - { - var origChildIndex = childIndex; - for (var index = startIndex; index < endIndexExcl; index++) - { - var frame = batch.ReferenceFrames.Array[index]; - var numChildrenInserted = InsertFrame(batch, parent, childIndex, frames, frame, index); - childIndex += numChildrenInserted; - - // Skip over any descendants, since they are already dealt with recursively - index += CountDescendantFrames(frame); - } - - return (childIndex - origChildIndex); // Total number of children inserted - } - - private void InsertElement(RenderBatch batch, ContainerNode parent, int childIndex, ArraySegment frames, RenderTreeFrame frame, int frameIndex) - { - // Note: we don't handle SVG here - var newElement = new ElementNode(frame.ElementName); - parent.InsertLogicalChild(newElement, childIndex); - - // Apply attributes - for (var i = frameIndex + 1; i < frameIndex + frame.ElementSubtreeLength; i++) - { - var descendantFrame = batch.ReferenceFrames.Array[i]; - if (descendantFrame.FrameType == RenderTreeFrameType.Attribute) - { - ApplyAttribute(batch, newElement, descendantFrame); - } - else - { - // As soon as we see a non-attribute child, all the subsequent child frames are - // not attributes, so bail out and insert the remnants recursively - InsertFrameRange(batch, newElement, 0, frames, i, frameIndex + frame.ElementSubtreeLength); - break; - } - } - } - - private void ApplyAttribute(RenderBatch batch, ElementNode elementNode, RenderTreeFrame attributeFrame) - { - var attributeName = attributeFrame.AttributeName; - var eventHandlerId = attributeFrame.AttributeEventHandlerId; - - if (eventHandlerId != 0) - { - var firstTwoChars = attributeName.Substring(0, 2); - var eventName = attributeName.Substring(2); - if (firstTwoChars != "on" || string.IsNullOrEmpty(eventName)) - { - throw new InvalidOperationException($"Attribute has nonzero event handler ID, but attribute name '${attributeName}' does not start with 'on'."); - } - var descriptor = new ElementNode.ElementEventDescriptor(eventName, eventHandlerId); - elementNode.SetEvent(eventName, descriptor); - - return; - } - - // First see if we have special handling for this attribute - if (!TryApplySpecialProperty(batch, elementNode, attributeName, attributeFrame)) - { - // If not, treat it as a regular string-valued attribute - elementNode.SetAttribute( - attributeName, - attributeFrame.AttributeValue); - } - } - - private bool TryApplySpecialProperty(RenderBatch batch, ElementNode element, string attributeName, RenderTreeFrame attributeFrame) - { - switch (attributeName) - { - case "value": - return TryApplyValueProperty(element, attributeFrame); - case "checked": - return TryApplyCheckedProperty(element, attributeFrame); - default: - return false; - } - } - - - - private bool TryApplyValueProperty(ElementNode element, RenderTreeFrame attributeFrame) - { - // Certain elements have built-in behaviour for their 'value' property - switch (element.TagName) - { - case "INPUT": - case "SELECT": - case "TEXTAREA": - { - var value = attributeFrame.AttributeValue; - element.SetProperty("value", value); - - if (element.TagName == "SELECT") - { - // s in some browsers, due to the limited stylability of ``s in IE10+.\n &::-ms-expand {\n background-color: transparent;\n border: 0;\n }\n\n // Customize the `:focus` state to imitate native WebKit styles.\n @include form-control-focus();\n\n // Placeholder\n &::placeholder {\n color: $input-placeholder-color;\n // Override Firefox's unusual default opacity; see https://github.com/twbs/bootstrap/pull/11526.\n opacity: 1;\n }\n\n // Disabled and read-only inputs\n //\n // HTML5 says that controls under a fieldset > legend:first-child won't be\n // disabled if the fieldset is disabled. Due to implementation difficulty, we\n // don't honor that edge case; we style them as disabled anyway.\n &:disabled,\n &[readonly] {\n background-color: $input-disabled-bg;\n // iOS fix for unreadable disabled content; see https://github.com/twbs/bootstrap/issues/11655.\n opacity: 1;\n }\n}\n\nselect.form-control {\n &:focus::-ms-value {\n // Suppress the nested default white text on blue background highlight given to\n // the selected option text when the (still closed) receives focus\n // in IE and (under certain conditions) Edge.\n // See https://github.com/twbs/bootstrap/issues/19398.\n color: $input-color;\n background-color: $input-bg;\n }\n }\n\n &[multiple],\n &[size]:not([size=\"1\"]) {\n height: auto;\n padding-right: $custom-select-padding-x;\n background-image: none;\n }\n\n &:disabled {\n color: $custom-select-disabled-color;\n background-color: $custom-select-disabled-bg;\n }\n\n // Hides the default caret in IE11\n &::-ms-expand {\n display: none;\n }\n}\n\n.custom-select-sm {\n height: $custom-select-height-sm;\n padding-top: $custom-select-padding-y-sm;\n padding-bottom: $custom-select-padding-y-sm;\n padding-left: $custom-select-padding-x-sm;\n @include font-size($custom-select-font-size-sm);\n}\n\n.custom-select-lg {\n height: $custom-select-height-lg;\n padding-top: $custom-select-padding-y-lg;\n padding-bottom: $custom-select-padding-y-lg;\n padding-left: $custom-select-padding-x-lg;\n @include font-size($custom-select-font-size-lg);\n}\n\n\n// File\n//\n// Custom file input.\n\n.custom-file {\n position: relative;\n display: inline-block;\n width: 100%;\n height: $custom-file-height;\n margin-bottom: 0;\n}\n\n.custom-file-input {\n position: relative;\n z-index: 2;\n width: 100%;\n height: $custom-file-height;\n margin: 0;\n opacity: 0;\n\n &:focus ~ .custom-file-label {\n border-color: $custom-file-focus-border-color;\n box-shadow: $custom-file-focus-box-shadow;\n }\n\n &:disabled ~ .custom-file-label {\n background-color: $custom-file-disabled-bg;\n }\n\n @each $lang, $value in $custom-file-text {\n &:lang(#{$lang}) ~ .custom-file-label::after {\n content: $value;\n }\n }\n\n ~ .custom-file-label[data-browse]::after {\n content: attr(data-browse);\n }\n}\n\n.custom-file-label {\n position: absolute;\n top: 0;\n right: 0;\n left: 0;\n z-index: 1;\n height: $custom-file-height;\n padding: $custom-file-padding-y $custom-file-padding-x;\n font-family: $custom-file-font-family;\n font-weight: $custom-file-font-weight;\n line-height: $custom-file-line-height;\n color: $custom-file-color;\n background-color: $custom-file-bg;\n border: $custom-file-border-width solid $custom-file-border-color;\n @include border-radius($custom-file-border-radius);\n @include box-shadow($custom-file-box-shadow);\n\n &::after {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n z-index: 3;\n display: block;\n height: $custom-file-height-inner;\n padding: $custom-file-padding-y $custom-file-padding-x;\n line-height: $custom-file-line-height;\n color: $custom-file-button-color;\n content: \"Browse\";\n @include gradient-bg($custom-file-button-bg);\n border-left: inherit;\n @include border-radius(0 $custom-file-border-radius $custom-file-border-radius 0);\n }\n}\n\n// Range\n//\n// Style range inputs the same across browsers. Vendor-specific rules for pseudo\n// elements cannot be mixed. As such, there are no shared styles for focus or\n// active states on prefixed selectors.\n\n.custom-range {\n width: 100%;\n height: calc(#{$custom-range-thumb-height} + #{$custom-range-thumb-focus-box-shadow-width * 2});\n padding: 0; // Need to reset padding\n background-color: transparent;\n appearance: none;\n\n &:focus {\n outline: none;\n\n // Pseudo-elements must be split across multiple rulesets to have an effect.\n // No box-shadow() mixin for focus accessibility.\n &::-webkit-slider-thumb { box-shadow: $custom-range-thumb-focus-box-shadow; }\n &::-moz-range-thumb { box-shadow: $custom-range-thumb-focus-box-shadow; }\n &::-ms-thumb { box-shadow: $custom-range-thumb-focus-box-shadow; }\n }\n\n &::-moz-focus-outer {\n border: 0;\n }\n\n &::-webkit-slider-thumb {\n width: $custom-range-thumb-width;\n height: $custom-range-thumb-height;\n margin-top: ($custom-range-track-height - $custom-range-thumb-height) / 2; // Webkit specific\n @include gradient-bg($custom-range-thumb-bg);\n border: $custom-range-thumb-border;\n @include border-radius($custom-range-thumb-border-radius);\n @include box-shadow($custom-range-thumb-box-shadow);\n @include transition($custom-forms-transition);\n appearance: none;\n\n &:active {\n @include gradient-bg($custom-range-thumb-active-bg);\n }\n }\n\n &::-webkit-slider-runnable-track {\n width: $custom-range-track-width;\n height: $custom-range-track-height;\n color: transparent; // Why?\n cursor: $custom-range-track-cursor;\n background-color: $custom-range-track-bg;\n border-color: transparent;\n @include border-radius($custom-range-track-border-radius);\n @include box-shadow($custom-range-track-box-shadow);\n }\n\n &::-moz-range-thumb {\n width: $custom-range-thumb-width;\n height: $custom-range-thumb-height;\n @include gradient-bg($custom-range-thumb-bg);\n border: $custom-range-thumb-border;\n @include border-radius($custom-range-thumb-border-radius);\n @include box-shadow($custom-range-thumb-box-shadow);\n @include transition($custom-forms-transition);\n appearance: none;\n\n &:active {\n @include gradient-bg($custom-range-thumb-active-bg);\n }\n }\n\n &::-moz-range-track {\n width: $custom-range-track-width;\n height: $custom-range-track-height;\n color: transparent;\n cursor: $custom-range-track-cursor;\n background-color: $custom-range-track-bg;\n border-color: transparent; // Firefox specific?\n @include border-radius($custom-range-track-border-radius);\n @include box-shadow($custom-range-track-box-shadow);\n }\n\n &::-ms-thumb {\n width: $custom-range-thumb-width;\n height: $custom-range-thumb-height;\n margin-top: 0; // Edge specific\n margin-right: $custom-range-thumb-focus-box-shadow-width; // Workaround that overflowed box-shadow is hidden.\n margin-left: $custom-range-thumb-focus-box-shadow-width; // Workaround that overflowed box-shadow is hidden.\n @include gradient-bg($custom-range-thumb-bg);\n border: $custom-range-thumb-border;\n @include border-radius($custom-range-thumb-border-radius);\n @include box-shadow($custom-range-thumb-box-shadow);\n @include transition($custom-forms-transition);\n appearance: none;\n\n &:active {\n @include gradient-bg($custom-range-thumb-active-bg);\n }\n }\n\n &::-ms-track {\n width: $custom-range-track-width;\n height: $custom-range-track-height;\n color: transparent;\n cursor: $custom-range-track-cursor;\n background-color: transparent;\n border-color: transparent;\n border-width: $custom-range-thumb-height / 2;\n @include box-shadow($custom-range-track-box-shadow);\n }\n\n &::-ms-fill-lower {\n background-color: $custom-range-track-bg;\n @include border-radius($custom-range-track-border-radius);\n }\n\n &::-ms-fill-upper {\n margin-right: 15px; // arbitrary?\n background-color: $custom-range-track-bg;\n @include border-radius($custom-range-track-border-radius);\n }\n\n &:disabled {\n &::-webkit-slider-thumb {\n background-color: $custom-range-thumb-disabled-bg;\n }\n\n &::-webkit-slider-runnable-track {\n cursor: default;\n }\n\n &::-moz-range-thumb {\n background-color: $custom-range-thumb-disabled-bg;\n }\n\n &::-moz-range-track {\n cursor: default;\n }\n\n &::-ms-thumb {\n background-color: $custom-range-thumb-disabled-bg;\n }\n }\n}\n\n.custom-control-label::before,\n.custom-file-label,\n.custom-select {\n @include transition($custom-forms-transition);\n}\n","// Base class\n//\n// Kickstart any navigation component with a set of style resets. Works with\n// `