Merge pull request #15084 from aspnet/merge/release/3.1-to-master

Merge/release/3.1 to master
This commit is contained in:
Pranav K 2019-10-23 16:15:33 -07:00 committed by GitHub
commit 602cb1dea5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
241 changed files with 3834 additions and 1961 deletions

View File

@ -46,7 +46,8 @@
<!-- Contact email address for NuGet packages and Linux installers. -->
<MaintainerEmail>nugetaspnet@microsoft.com</MaintainerEmail>
<PackageIconUrl>https://go.microsoft.com/fwlink/?LinkID=288859</PackageIconUrl>
<PackageIcon>packageIcon.png</PackageIcon>
<PackageIconFullPath>$(MSBuildThisFileDirectory)packageIcon.png</PackageIconFullPath>
<PackageProjectUrl>https://asp.net</PackageProjectUrl>
<NuspecBasePath>$(MSBuildProjectDirectory)</NuspecBasePath>
@ -55,6 +56,10 @@
<DefaultNetCoreTargetFramework>netcoreapp5.0</DefaultNetCoreTargetFramework>
</PropertyGroup>
<ItemGroup>
<None Include="$(PackageIconFullPath)" Pack="true" PackagePath="\"/>
</ItemGroup>
<!-- Warnings and errors -->
<PropertyGroup>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
@ -90,7 +95,7 @@
<TargetingPackInstallerBaseName>aspnetcore-targeting-pack</TargetingPackInstallerBaseName>
<!-- Used to only produce targeting pack installers/packages once per major.minor. -->
<IsTargetingPackBuilding Condition="'$(IsServicingBuild)' == 'true' AND '$(DotNetBuildFromSource)' != 'true'">false</IsTargetingPackBuilding>
<IsTargetingPackBuilding Condition="'$(AspNetCorePatchVersion)' != '0' OR '$(DotNetBuildFromSource)' == 'true'">false</IsTargetingPackBuilding>
<!--
Archives and installers using this prefix are intended for internal-use only.

View File

@ -58,7 +58,8 @@
<Import Project="eng\Baseline.Designer.props" />
<PropertyGroup Condition=" '$(IsPackable)' != 'false' AND '$(AspNetCorePatchVersion)' != '0' ">
<PropertyGroup
Condition=" '$(IsPackable)' != 'false' AND '$(AspNetCorePatchVersion)' != '0' AND '$(DisableServicingFeatures)' != 'true' ">
<IsPackageInThisPatch Condition="'$(IsPackageInThisPatch)' == ''">$(PackagesInPatch.Contains(' $(PackageId);'))</IsPackageInThisPatch>
</PropertyGroup>
@ -104,6 +105,12 @@
<Compile Include="$(SharedSourceRoot)ReferenceAssemblyInfo.cs" LinkBase="Properties" />
</ItemGroup>
<PropertyGroup Condition="'$(Language)' == 'C#'">
<!-- Reference assemblies should always use Major.Minor.0.0 for assembly versions even during servicing. Only the package version should be updated. -->
<!-- Pinning the implementation assemblies at Major.Minor.0.0 as we figure out compiling against ref assemblies. -->
<AssemblyVersion>$(AspNetCoreMajorVersion).$(AspNetCoreMinorVersion).0.0</AssemblyVersion>
</PropertyGroup>
<ItemGroup>
<KnownFrameworkReference Update="Microsoft.NETCore.App">
<!-- Always update the 'latest version', whether the repo is servicing or not. -->

View File

@ -6,6 +6,7 @@
<add key="darc-pub-dotnet-corefx-4ac4c03" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/darc-pub-dotnet-corefx-4ac4c036/nuget/v3/index.json" />
<!--End: Package sources managed by Dependency Flow automation. Do not edit the sources above.-->
<add key="dotnet-core" value="https://dotnetfeed.blob.core.windows.net/dotnet-core/index.json" />
<add key="dotnet-tools" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json" />
<add key="aspnet-blazor" value="https://dotnetfeed.blob.core.windows.net/aspnet-blazor/index.json" />
<add key="aspnet-extensions" value="https://dotnetfeed.blob.core.windows.net/aspnet-extensions/index.json" />
<add key="aspnet-entityframeworkcore" value="https://dotnetfeed.blob.core.windows.net/aspnet-entityframeworkcore/index.json" />

File diff suppressed because it is too large Load Diff

View File

@ -1,138 +1,91 @@
<!--
This file contains a list of all the packages and their versions which were released in the last servicing
build of ASP.NET Core 2.2.x. Update this list when preparing for a new patch.
This file contains a list of all the packages and their versions which were released in ASP.NET Core 3.0.0.
Update this list when preparing for a new patch.
-->
<Baseline Version="2.2.7">
<Package Id="dotnet-dev-certs" Version="2.2.0" />
<Package Id="dotnet-sql-cache" Version="2.2.0" />
<Package Id="dotnet-user-secrets" Version="2.2.0" />
<Package Id="dotnet-watch" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Antiforgery" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.ApiAuthorization.IdentityServer" Version="2.2.0-preview-35687" />
<Package Id="Microsoft.AspNetCore.ApplicationInsights.HostingStartup" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.AspNetCoreModule" Version="2.2.7" />
<Package Id="Microsoft.AspNetCore.AspNetCoreModuleV2" Version="2.2.7" />
<Package Id="Microsoft.AspNetCore.Authentication.Abstractions" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Authentication.AzureAD.UI" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Authentication.AzureADB2C.UI" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Authentication.Cookies" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Authentication.Core" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Authentication.Facebook" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Authentication.Google" Version="2.2.2" />
<Package Id="Microsoft.AspNetCore.Authentication.JwtBearer" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Authentication.MicrosoftAccount" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Authentication.OAuth" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Authentication.Twitter" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Authentication.WsFederation" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Authentication" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Authorization.Policy" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Authorization" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.AzureAppServices.HostingStartup" Version="2.2.5" />
<Package Id="Microsoft.AspNetCore.AzureAppServicesIntegration" Version="2.2.5" />
<Package Id="Microsoft.AspNetCore.Connections.Abstractions" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.CookiePolicy" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Cors" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Cryptography.Internal" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.DataProtection.Abstractions" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.DataProtection.AzureKeyVault" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.DataProtection.AzureStorage" Version="2.2.7" />
<Package Id="Microsoft.AspNetCore.DataProtection.EntityFrameworkCore" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.DataProtection.Extensions" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.DataProtection.StackExchangeRedis" Version="2.2.5" />
<Package Id="Microsoft.AspNetCore.DataProtection.SystemWeb" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.DataProtection" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Diagnostics.Abstractions" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="2.2.1" />
<Package Id="Microsoft.AspNetCore.Diagnostics.HealthChecks" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Diagnostics" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.HostFiltering" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Hosting.Abstractions" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Hosting.Server.Abstractions" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Hosting.WindowsServices" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Hosting" Version="2.2.7" />
<Package Id="Microsoft.AspNetCore.Html.Abstractions" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Http.Abstractions" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Http.Connections.Client" Version="1.1.0" />
<Package Id="Microsoft.AspNetCore.Http.Connections.Common" Version="1.1.0" />
<Package Id="Microsoft.AspNetCore.Http.Connections" Version="1.1.0" />
<Package Id="Microsoft.AspNetCore.Http.Extensions" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Http.Features" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Http" Version="2.2.2" />
<Package Id="Microsoft.AspNetCore.HttpOverrides" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.HttpsPolicy" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Identity.Specification.Tests" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Identity.UI" Version="2.2.5" />
<Package Id="Microsoft.AspNetCore.Identity" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.JsonPatch" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Localization.Routing" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Localization" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.MiddlewareAnalysis" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Mvc.Abstractions" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Mvc.Analyzers" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Mvc.Api.Analyzers" Version="2.2.6" />
<Package Id="Microsoft.AspNetCore.Mvc.ApiExplorer" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Mvc.Core" Version="2.2.5" />
<Package Id="Microsoft.AspNetCore.Mvc.Cors" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Mvc.DataAnnotations" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Mvc.Formatters.Json" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Mvc.Formatters.Xml" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Mvc.Localization" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Mvc.Razor.Extensions" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Mvc.Razor" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Mvc.RazorPages" Version="2.2.5" />
<Package Id="Microsoft.AspNetCore.Mvc.TagHelpers" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Mvc.Testing" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Mvc.ViewFeatures" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Mvc" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.NodeServices" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Owin" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Razor.Design" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Razor.Language" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Razor.Runtime" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Razor" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.ResponseCaching.Abstractions" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.ResponseCaching" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.ResponseCompression" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Rewrite" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Routing.Abstractions" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Routing" Version="2.2.2" />
<Package Id="Microsoft.AspNetCore.Server.HttpSys" Version="2.2.6" />
<Package Id="Microsoft.AspNetCore.Server.IIS" Version="2.2.6" />
<Package Id="Microsoft.AspNetCore.Server.IISIntegration" Version="2.2.1" />
<Package Id="Microsoft.AspNetCore.Server.Kestrel.Core" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Server.Kestrel.Https" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets" Version="2.2.1" />
<Package Id="Microsoft.AspNetCore.Server.Kestrel" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Session" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.SignalR.Client.Core" Version="1.1.0" />
<Package Id="Microsoft.AspNetCore.SignalR.Client" Version="1.1.0" />
<Package Id="Microsoft.AspNetCore.SignalR.Common" Version="1.1.0" />
<Package Id="Microsoft.AspNetCore.SignalR.Core" Version="1.1.0" />
<Package Id="Microsoft.AspNetCore.SignalR.Protocols.Json" Version="1.1.0" />
<Package Id="Microsoft.AspNetCore.SignalR.Protocols.MessagePack" Version="1.1.5" />
<Package Id="Microsoft.AspNetCore.SignalR.Redis" Version="1.1.5" />
<Package Id="Microsoft.AspNetCore.SignalR.Specification.Tests" Version="1.1.0" />
<Package Id="Microsoft.AspNetCore.SignalR.StackExchangeRedis" Version="1.1.5" />
<Package Id="Microsoft.AspNetCore.SignalR" Version="1.1.0" />
<Package Id="Microsoft.AspNetCore.SpaServices.Extensions" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.SpaServices" Version="2.2.7" />
<Package Id="Microsoft.AspNetCore.StaticFiles" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.TestHost" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.WebSockets" Version="2.2.1" />
<Package Id="Microsoft.AspNetCore.WebUtilities" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore" Version="2.2.0" />
<Package Id="Microsoft.CodeAnalysis.Razor" Version="2.2.0" />
<Package Id="Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore" Version="2.2.0" />
<Package Id="Microsoft.Extensions.Identity.Core" Version="2.2.0" />
<Package Id="Microsoft.Extensions.Identity.Stores" Version="2.2.0" />
<Package Id="Microsoft.Net.Http.Headers" Version="2.2.0" />
<Package Id="Microsoft.Net.Sdk.Razor" Version="2.2.0" />
<Package Id="Microsoft.Owin.Security.Interop" Version="2.2.0" />
<Baseline Version="3.0.0">
<Package Id="AspNetCoreRuntime.3.0.x64" Version="3.0.0" />
<Package Id="AspNetCoreRuntime.3.0.x86" Version="3.0.0" />
<Package Id="dotnet-sql-cache" Version="3.0.0" />
<Package Id="Microsoft.AspNetCore.ApiAuthorization.IdentityServer" Version="3.0.0" />
<Package Id="Microsoft.AspNetCore.App.Runtime.win-x64" Version="3.0.0" />
<Package Id="Microsoft.AspNetCore.Authentication.AzureAD.UI" Version="3.0.0" />
<Package Id="Microsoft.AspNetCore.Authentication.AzureADB2C.UI" Version="3.0.0" />
<Package Id="Microsoft.AspNetCore.Authentication.Certificate" Version="3.0.0" />
<Package Id="Microsoft.AspNetCore.Authentication.Facebook" Version="3.0.0" />
<Package Id="Microsoft.AspNetCore.Authentication.Google" Version="3.0.0" />
<Package Id="Microsoft.AspNetCore.Authentication.JwtBearer" Version="3.0.0" />
<Package Id="Microsoft.AspNetCore.Authentication.MicrosoftAccount" Version="3.0.0" />
<Package Id="Microsoft.AspNetCore.Authentication.Negotiate" Version="3.0.0" />
<Package Id="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="3.0.0" />
<Package Id="Microsoft.AspNetCore.Authentication.Twitter" Version="3.0.0" />
<Package Id="Microsoft.AspNetCore.Authentication.WsFederation" Version="3.0.0" />
<Package Id="Microsoft.AspNetCore.Authorization" Version="3.0.0" />
<Package Id="Microsoft.AspNetCore.AzureAppServices.HostingStartup" Version="3.0.0" />
<Package Id="Microsoft.AspNetCore.AzureAppServices.SiteExtension" Version="3.0.0" />
<Package Id="Microsoft.AspNetCore.AzureAppServicesIntegration" Version="3.0.0" />
<Package Id="Microsoft.AspNetCore.Blazor" Version="3.0.0-preview9.19465.2" />
<Package Id="Microsoft.AspNetCore.Blazor.Build" Version="3.0.0-preview9.19465.2" />
<Package Id="Microsoft.AspNetCore.Blazor.DevServer" Version="3.0.0-preview9.19465.2" />
<Package Id="Microsoft.AspNetCore.Blazor.HttpClient" Version="3.0.0-preview9.19465.2" />
<Package Id="Microsoft.AspNetCore.Blazor.Server" Version="3.0.0-preview9.19465.2" />
<Package Id="Microsoft.AspNetCore.Blazor.Templates" Version="3.0.0-preview9.19465.2" />
<Package Id="Microsoft.AspNetCore.Components" Version="3.0.0" />
<Package Id="Microsoft.AspNetCore.Components.Analyzers" Version="3.0.0" />
<Package Id="Microsoft.AspNetCore.Components.Authorization" Version="3.0.0" />
<Package Id="Microsoft.AspNetCore.Components.Forms" Version="3.0.0" />
<Package Id="Microsoft.AspNetCore.Components.Web" Version="3.0.0" />
<Package Id="Microsoft.AspNetCore.ConcurrencyLimiter" Version="3.0.0" />
<Package Id="Microsoft.AspNetCore.Connections.Abstractions" Version="3.0.0" />
<Package Id="Microsoft.AspNetCore.Cryptography.Internal" Version="3.0.0" />
<Package Id="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="3.0.0" />
<Package Id="Microsoft.AspNetCore.DataProtection" Version="3.0.0" />
<Package Id="Microsoft.AspNetCore.DataProtection.Abstractions" Version="3.0.0" />
<Package Id="Microsoft.AspNetCore.DataProtection.AzureKeyVault" Version="3.0.0" />
<Package Id="Microsoft.AspNetCore.DataProtection.AzureStorage" Version="3.0.0" />
<Package Id="Microsoft.AspNetCore.DataProtection.EntityFrameworkCore" Version="3.0.0" />
<Package Id="Microsoft.AspNetCore.DataProtection.Extensions" Version="3.0.0" />
<Package Id="Microsoft.AspNetCore.DataProtection.StackExchangeRedis" Version="3.0.0" />
<Package Id="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="3.0.0" />
<Package Id="Microsoft.AspNetCore.HeaderPropagation" Version="3.0.0" />
<Package Id="Microsoft.AspNetCore.Hosting.WindowsServices" Version="3.0.0" />
<Package Id="Microsoft.AspNetCore.Http.Connections.Client" Version="3.0.0" />
<Package Id="Microsoft.AspNetCore.Http.Connections.Common" Version="3.0.0" />
<Package Id="Microsoft.AspNetCore.Http.Features" Version="3.0.0" />
<Package Id="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="3.0.0" />
<Package Id="Microsoft.AspNetCore.Identity.Specification.Tests" Version="3.0.0" />
<Package Id="Microsoft.AspNetCore.Identity.UI" Version="3.0.0" />
<Package Id="Microsoft.AspNetCore.JsonPatch" Version="3.0.0" />
<Package Id="Microsoft.AspNetCore.Metadata" Version="3.0.0" />
<Package Id="Microsoft.AspNetCore.MiddlewareAnalysis" Version="3.0.0" />
<Package Id="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.0.0" />
<Package Id="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="3.0.0" />
<Package Id="Microsoft.AspNetCore.Mvc.Testing" Version="3.0.0" />
<Package Id="Microsoft.AspNetCore.NodeServices" Version="3.0.0" />
<Package Id="Microsoft.AspNetCore.Owin" Version="3.0.0" />
<Package Id="Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv" Version="3.0.0" />
<Package Id="Microsoft.AspNetCore.SignalR.Client" Version="3.0.0" />
<Package Id="Microsoft.AspNetCore.SignalR.Client.Core" Version="3.0.0" />
<Package Id="Microsoft.AspNetCore.SignalR.Common" Version="3.0.0" />
<Package Id="Microsoft.AspNetCore.SignalR.Protocols.Json" Version="3.0.0" />
<Package Id="Microsoft.AspNetCore.SignalR.Protocols.MessagePack" Version="3.0.0" />
<Package Id="Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson" Version="3.0.0" />
<Package Id="Microsoft.AspNetCore.SignalR.Specification.Tests" Version="3.0.0" />
<Package Id="Microsoft.AspNetCore.SignalR.StackExchangeRedis" Version="3.0.0" />
<Package Id="Microsoft.AspNetCore.SpaServices" Version="3.0.0" />
<Package Id="Microsoft.AspNetCore.SpaServices.Extensions" Version="3.0.0" />
<Package Id="Microsoft.AspNetCore.TestHost" Version="3.0.0" />
<Package Id="Microsoft.dotnet-openapi" Version="3.0.0" />
<Package Id="Microsoft.DotNet.Web.Client.ItemTemplates" Version="3.0.0" />
<Package Id="Microsoft.DotNet.Web.ItemTemplates" Version="3.0.0" />
<Package Id="Microsoft.DotNet.Web.ProjectTemplates.3.0" Version="3.0.0" />
<Package Id="Microsoft.DotNet.Web.Spa.ProjectTemplates.3.0" Version="3.0.0" />
<Package Id="Microsoft.Extensions.ApiDescription.Client" Version="3.0.0" />
<Package Id="Microsoft.Extensions.ApiDescription.Server" Version="3.0.0" />
<Package Id="Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore" Version="3.0.0" />
<Package Id="Microsoft.Extensions.Identity.Core" Version="3.0.0" />
<Package Id="Microsoft.Extensions.Identity.Stores" Version="3.0.0" />
</Baseline>

View File

@ -4,8 +4,8 @@ This file contains a list of the package IDs which are patching in a given relea
CAUTION: due to limitations in MSBuild, the format of the PackagesInPatch property is picky.
When adding a new package, make sure the new line ends with a semicolon and starts with a space.
Later on, this will be checked using this condition:
Directory.Build.props checks this property using the following condition:
<IsPackageInThisPatch>$(PackagesInPatch.Contains(' $(PackageId);'))</IsPackageInThisPatch>
-->
<Project>
@ -15,59 +15,14 @@ Later on, this will be checked using this condition:
<PropertyGroup Condition=" '$(VersionPrefix)' == '3.0.1' ">
<PackagesInPatch>
</PackagesInPatch>
</PropertyGroup>
<PropertyGroup Condition=" '$(VersionPrefix)' == '2.2.2' ">
<PackagesInPatch>
@aspnet/signalr;
Microsoft.AspNetCore.AspNetCoreModuleV2;
Microsoft.AspNetCore.Authentication.Google;
Microsoft.AspNetCore.Http;
Microsoft.AspNetCore.Mvc.Core;
Microsoft.AspNetCore.Routing;
Microsoft.AspNetCore.Server.IIS;
java:signalr;
</PackagesInPatch>
</PropertyGroup>
<PropertyGroup Condition=" '$(VersionPrefix)' == '2.2.4' ">
<PackagesInPatch>
@aspnet/signalr;
Microsoft.AspNetCore.AspNetCoreModuleV2;
</PackagesInPatch>
</PropertyGroup>
<PropertyGroup Condition=" '$(VersionPrefix)' == '2.2.5' ">
<PackagesInPatch>
Microsoft.AspNetCore.AspNetCoreModule;
Microsoft.AspNetCore.AspNetCoreModuleV2;
Microsoft.AspNetCore.Identity.UI;
java:signalr;
Microsoft.AspNetCore.SignalR.Protocols.MessagePack;
Microsoft.AspNetCore.SignalR.Redis;
Microsoft.AspNetCore.SignalR.StackExchangeRedis;
Microsoft.AspNetCore.DataProtection.StackExchangeRedis;
Microsoft.AspNetCore.Mvc.Core;
Microsoft.AspNetCore.Mvc.RazorPages;
Microsoft.AspNetCore.AzureAppServicesIntegration;
Microsoft.AspNetCore.AzureAppServices.HostingStartup;
Microsoft.AspNetCore.AzureAppServices.SiteExtension;
</PackagesInPatch>
</PropertyGroup>
<PropertyGroup Condition=" '$(VersionPrefix)' == '2.2.6' ">
<PackagesInPatch>
Microsoft.AspNetCore.Mvc.Api.Analyzers;
Microsoft.AspNetCore.Server.HttpSys;
Microsoft.AspNetCore.Server.IIS;
</PackagesInPatch>
</PropertyGroup>
<PropertyGroup Condition=" '$(VersionPrefix)' == '2.2.7' ">
<PackagesInPatch>
Microsoft.AspNetCore.DataProtection.AzureStorage;
Microsoft.AspNetCore.Hosting;
Microsoft.AspNetCore.SpaServices;
</PackagesInPatch>
</PropertyGroup>
<PropertyGroup Condition=" '$(VersionPrefix)' == '2.2.8' ">
<PackagesInPatch>
Microsoft.Net.Http.Headers;
Microsoft.AspNetCore.CookiePolicy;
Microsoft.AspNetCore.DataProtection.EntityFrameworkCore;
@microsoft/signalr;
Microsoft.Net.Http.Headers;
Microsoft.AspNetCore.Http.Abstractions;
Microsoft.AspNetCore.Http.Features;
Microsoft.AspNetCore.CookiePolicy;
</PackagesInPatch>
</PropertyGroup>
</Project>

View File

@ -412,17 +412,17 @@
<Uri>https://github.com/aspnet/Extensions</Uri>
<Sha>f15f3278c73c72a6546d7cb2c1bd54a541ffc83e</Sha>
</Dependency>
<Dependency Name="Microsoft.DotNet.GenAPI" Version="1.0.0-beta.19462.4">
<Dependency Name="Microsoft.DotNet.GenAPI" Version="1.0.0-beta.19510.3">
<Uri>https://github.com/dotnet/arcade</Uri>
<Sha>f8546fbab59a74a66c83b8cb76b3f6877ce1d374</Sha>
<Sha>f70d1fca3d5d4045be75694006f1bee0e0aec572</Sha>
</Dependency>
<Dependency Name="Microsoft.DotNet.Arcade.Sdk" Version="1.0.0-beta.19462.4">
<Dependency Name="Microsoft.DotNet.Arcade.Sdk" Version="1.0.0-beta.19510.3">
<Uri>https://github.com/dotnet/arcade</Uri>
<Sha>f8546fbab59a74a66c83b8cb76b3f6877ce1d374</Sha>
<Sha>f70d1fca3d5d4045be75694006f1bee0e0aec572</Sha>
</Dependency>
<Dependency Name="Microsoft.DotNet.Helix.Sdk" Version="2.0.0-beta.19462.4">
<Dependency Name="Microsoft.DotNet.Helix.Sdk" Version="2.0.0-beta.19510.3">
<Uri>https://github.com/dotnet/arcade</Uri>
<Sha>f8546fbab59a74a66c83b8cb76b3f6877ce1d374</Sha>
<Sha>f70d1fca3d5d4045be75694006f1bee0e0aec572</Sha>
</Dependency>
<Dependency Name="Microsoft.AspNetCore.Testing" Version="5.0.0-alpha1.19517.7" CoherentParentDependency="Microsoft.EntityFrameworkCore">
<Uri>https://github.com/aspnet/Extensions</Uri>

View File

@ -20,8 +20,15 @@
<AspNetCoreMajorMinorVersion>$(AspNetCoreMajorVersion).$(AspNetCoreMinorVersion)</AspNetCoreMajorMinorVersion>
<!-- Additional assembly attributes are already configured to include the source revision ID. -->
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
<!--
Until package baselines are updated (see aspnet/AspNetCore#12702), ignore them and PatchConfig.props. This also
gives us time to build the entire repo and settle the infrastructure. Do _not_ do this when stabilizing versions.
-->
<DisableServicingFeatures
Condition=" '$(DisableServicingFeatures)' == '' AND '$(StabilizePackageVersion)' != 'true' ">true</DisableServicingFeatures>
<!-- Servicing builds have different characteristics for the way dependencies, baselines, and versions are handled. -->
<IsServicingBuild Condition=" '$(PreReleaseVersionLabel)' == 'servicing' ">true</IsServicingBuild>
<IsServicingBuild
Condition=" '$(DisableServicingFeatures)' != 'true' AND '$(PreReleaseVersionLabel)' == 'servicing' ">true</IsServicingBuild>
<VersionPrefix>$(AspNetCoreMajorVersion).$(AspNetCoreMinorVersion).$(AspNetCorePatchVersion)</VersionPrefix>
<!-- TargetingPackVersionPrefix is used by projects, like .deb and .rpm, which use slightly different version formats. -->
<TargetingPackVersionPrefix>$(VersionPrefix)</TargetingPackVersionPrefix>
@ -55,7 +62,7 @@
-->
<PropertyGroup Label="Automated">
<!-- Packages from dotnet/arcade -->
<MicrosoftDotNetGenAPIPackageVersion>1.0.0-beta.19462.4</MicrosoftDotNetGenAPIPackageVersion>
<MicrosoftDotNetGenAPIPackageVersion>1.0.0-beta.19510.3</MicrosoftDotNetGenAPIPackageVersion>
<!-- Packages from dotnet/roslyn -->
<MicrosoftNetCompilersToolsetPackageVersion>3.4.0-beta1-19456-03</MicrosoftNetCompilersToolsetPackageVersion>
<!-- Packages from dotnet/core-setup -->
@ -229,7 +236,7 @@
<CastleCorePackageVersion>4.2.1</CastleCorePackageVersion>
<FSharpCorePackageVersion>4.2.1</FSharpCorePackageVersion>
<GoogleProtobufPackageVersion>3.8.0</GoogleProtobufPackageVersion>
<GrpcAspNetCorePackageVersion>2.23.1</GrpcAspNetCorePackageVersion>
<GrpcAspNetCorePackageVersion>2.23.2</GrpcAspNetCorePackageVersion>
<IdentityServer4AspNetIdentityPackageVersion>3.0.0</IdentityServer4AspNetIdentityPackageVersion>
<IdentityServer4EntityFrameworkPackageVersion>3.0.0</IdentityServer4EntityFrameworkPackageVersion>
<IdentityServer4PackageVersion>3.0.0</IdentityServer4PackageVersion>

View File

@ -21,6 +21,8 @@
<PropertyGroup>
<!-- Working around https://github.com/NuGet/Home/issues/8467 -->
<NoWarn>$(NoWarn);NU5131</NoWarn>
<!-- Workaround until https://github.com/aspnet/AspNetCore-Internal/issues/3103 is resolved -->
<NoWarn>$(NoWarn);NU5048</NoWarn>
</PropertyGroup>
<!-- Workaround https://github.com/dotnet/roslyn/issues/27975 -->

View File

@ -0,0 +1,6 @@
param(
[string] $token
)
Write-Host "##vso[task.setvariable variable=VSS_NUGET_ACCESSTOKEN]$token"
Write-Host "##vso[task.setvariable variable=VSS_NUGET_URI_PREFIXES]https://dnceng.pkgs.visualstudio.com/;https://pkgs.dev.azure.com/dnceng/;https://devdiv.pkgs.visualstudio.com/;https://pkgs.dev.azure.com/devdiv/"

View File

@ -5,6 +5,13 @@ param(
$ErrorActionPreference = "Stop"
Set-StrictMode -Version 2.0
# `tools.ps1` checks $ci to perform some actions. Since the post-build
# scripts don't necessarily execute in the same agent that run the
# build.ps1/sh script this variable isn't automatically set.
$ci = $true
. $PSScriptRoot\..\tools.ps1
$ExtractPackage = {
param(
[string] $PackagePath # Full path to a NuGet package

View File

@ -0,0 +1,95 @@
parameters:
artifactsPublishingAdditionalParameters: ''
publishInstallersAndChecksums: false
stages:
- stage: NetCore_3_Tools_Validation_Publish
dependsOn: validate
variables:
- template: ../common-variables.yml
displayName: .NET 3 Tools - Validation Publishing
jobs:
- template: ../setup-maestro-vars.yml
- job: publish_assets
displayName: Publish Assets
dependsOn: setupMaestroVars
variables:
- group: DotNet-Blob-Feed
- group: AzureDevOps-Artifact-Feeds-Pats
- name: BARBuildId
value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.BARBuildId'] ]
- name: IsStableBuild
value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.IsStableBuild'] ]
condition: contains(dependencies.setupMaestroVars.outputs['setReleaseVars.InitialChannels'], format('[{0}]', variables.NETCore_3_Tools_Validation_Channel_Id))
pool:
vmImage: 'windows-2019'
steps:
- task: DownloadBuildArtifacts@0
displayName: Download Package Artifacts
inputs:
buildType: current
artifactName: PackageArtifacts
- task: DownloadBuildArtifacts@0
displayName: Download Blob Artifacts
inputs:
buildType: current
artifactName: BlobArtifacts
- task: DownloadBuildArtifacts@0
displayName: Download Asset Manifests
inputs:
buildType: current
artifactName: AssetManifests
- task: NuGetToolInstaller@1
displayName: 'Install NuGet.exe'
# This is necessary whenever we want to publish/restore to an AzDO private feed
- task: NuGetAuthenticate@0
displayName: 'Authenticate to AzDO Feeds'
- task: PowerShell@2
displayName: Enable cross-org publishing
inputs:
filePath: eng\common\enable-cross-org-publishing.ps1
arguments: -token $(dn-bot-dnceng-artifact-feeds-rw)
- task: PowerShell@2
displayName: Publish Assets
inputs:
filePath: eng\common\sdk-task.ps1
arguments: -task PublishArtifactsInManifest -restore -msbuildEngine dotnet
/p:ArtifactsCategory=$(_DotNetValidationArtifactsCategory)
/p:IsStableBuild=$(IsStableBuild)
/p:IsInternalBuild=$(IsInternalBuild)
/p:RepositoryName=$(Build.Repository.Name)
/p:CommitSha=$(Build.SourceVersion)
/p:NugetPath=$(NuGetExeToolPath)
/p:AzdoTargetFeedPAT='$(dn-bot-dnceng-universal-packages-rw)'
/p:AzureStorageTargetFeedPAT='$(dotnetfeed-storage-access-key-1)'
/p:BARBuildId=$(BARBuildId)
/p:MaestroApiEndpoint='$(MaestroApiEndPoint)'
/p:BuildAssetRegistryToken='$(MaestroApiAccessToken)'
/p:ManifestsBasePath='$(Build.ArtifactStagingDirectory)/AssetManifests/'
/p:BlobBasePath='$(Build.ArtifactStagingDirectory)/BlobArtifacts/'
/p:PackageBasePath='$(Build.ArtifactStagingDirectory)/PackageArtifacts/'
/p:Configuration=Release
/p:PublishInstallersAndChecksums=${{ parameters.publishInstallersAndChecksums }}
/p:InstallersTargetStaticFeed=$(InstallersBlobFeedUrl)
/p:InstallersAzureAccountKey=$(dotnetcli-storage-key)
/p:ChecksumsTargetStaticFeed=$(ChecksumsBlobFeedUrl)
/p:ChecksumsAzureAccountKey=$(dotnetclichecksums-storage-key)
/p:PublishToAzureDevOpsNuGetFeeds=true
/p:AzureDevOpsStaticShippingFeed='https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json'
/p:AzureDevOpsStaticShippingFeedKey='$(dn-bot-dnceng-artifact-feeds-rw)'
/p:AzureDevOpsStaticTransportFeed='https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json'
/p:AzureDevOpsStaticTransportFeedKey='$(dn-bot-dnceng-artifact-feeds-rw)'
/p:AzureDevOpsStaticSymbolsFeed='https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools-symbols/nuget/v3/index.json'
/p:AzureDevOpsStaticSymbolsFeedKey='$(dn-bot-dnceng-artifact-feeds-rw)'
${{ parameters.artifactsPublishingAdditionalParameters }}
- template: ../../steps/promote-build.yml
parameters:
ChannelId: ${{ variables.NETCore_3_Tools_Validation_Channel_Id }}

View File

@ -4,18 +4,18 @@ parameters:
publishInstallersAndChecksums: false
stages:
- stage: NetCore_Dev30_Publish
- stage: NetCore_3_Tools_Publish
dependsOn: validate
variables:
- template: ../common-variables.yml
displayName: .NET Core 3.0 Dev Publishing
displayName: .NET 3 Tools Publishing
jobs:
- template: ../setup-maestro-vars.yml
- job:
displayName: Symbol Publishing
dependsOn: setupMaestroVars
condition: contains(dependencies.setupMaestroVars.outputs['setReleaseVars.InitialChannels'], format('[{0}]', variables.PublicDevRelease_30_Channel_Id))
condition: contains(dependencies.setupMaestroVars.outputs['setReleaseVars.InitialChannels'], format('[{0}]', variables.NetCore_3_Tools_Channel_Id))
variables:
- group: DotNet-Symbol-Server-Pats
pool:
@ -56,7 +56,7 @@ stages:
value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.BARBuildId'] ]
- name: IsStableBuild
value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.IsStableBuild'] ]
condition: contains(dependencies.setupMaestroVars.outputs['setReleaseVars.InitialChannels'], format('[{0}]', variables.PublicDevRelease_30_Channel_Id))
condition: contains(dependencies.setupMaestroVars.outputs['setReleaseVars.InitialChannels'], format('[{0}]', variables.NetCore_3_Tools_Channel_Id))
pool:
vmImage: 'windows-2019'
steps:
@ -85,10 +85,14 @@ stages:
- task: NuGetAuthenticate@0
displayName: 'Authenticate to AzDO Feeds'
- task: PowerShell@2
displayName: Enable cross-org publishing
inputs:
filePath: eng\common\enable-cross-org-publishing.ps1
arguments: -token $(dn-bot-dnceng-artifact-feeds-rw)
- task: PowerShell@2
displayName: Publish Assets
env:
AZURE_DEVOPS_EXT_PAT: $(dn-bot-dnceng-universal-packages-rw)
inputs:
filePath: eng\common\sdk-task.ps1
arguments: -task PublishArtifactsInManifest -restore -msbuildEngine dotnet
@ -113,14 +117,14 @@ stages:
/p:ChecksumsTargetStaticFeed=$(ChecksumsBlobFeedUrl)
/p:ChecksumsAzureAccountKey=$(dotnetclichecksums-storage-key)
/p:PublishToAzureDevOpsNuGetFeeds=true
/p:AzureDevOpsStaticShippingFeed='https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet3/nuget/v3/index.json'
/p:AzureDevOpsStaticShippingFeed='https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json'
/p:AzureDevOpsStaticShippingFeedKey='$(dn-bot-dnceng-artifact-feeds-rw)'
/p:AzureDevOpsStaticTransportFeed='https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet3-transport/nuget/v3/index.json'
/p:AzureDevOpsStaticTransportFeed='https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json'
/p:AzureDevOpsStaticTransportFeedKey='$(dn-bot-dnceng-artifact-feeds-rw)'
/p:AzureDevOpsStaticSymbolsFeed='https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet3-symbols/nuget/v3/index.json'
/p:AzureDevOpsStaticSymbolsFeed='https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools-symbols/nuget/v3/index.json'
/p:AzureDevOpsStaticSymbolsFeedKey='$(dn-bot-dnceng-artifact-feeds-rw)'
${{ parameters.artifactsPublishingAdditionalParameters }}
- template: ../../steps/promote-build.yml
parameters:
ChannelId: ${{ variables.PublicDevRelease_30_Channel_Id }}
ChannelId: ${{ variables.NetCore_3_Tools_Channel_Id }}

View File

@ -85,10 +85,14 @@ stages:
- task: NuGetAuthenticate@0
displayName: 'Authenticate to AzDO Feeds'
- task: PowerShell@2
displayName: Enable cross-org publishing
inputs:
filePath: eng\common\enable-cross-org-publishing.ps1
arguments: -token $(dn-bot-dnceng-artifact-feeds-rw)
- task: PowerShell@2
displayName: Publish Assets
env:
AZURE_DEVOPS_EXT_PAT: $(dn-bot-dnceng-universal-packages-rw)
inputs:
filePath: eng\common\sdk-task.ps1
arguments: -task PublishArtifactsInManifest -restore -msbuildEngine dotnet

View File

@ -85,10 +85,14 @@ stages:
- task: NuGetAuthenticate@0
displayName: 'Authenticate to AzDO Feeds'
- task: PowerShell@2
displayName: Enable cross-org publishing
inputs:
filePath: eng\common\enable-cross-org-publishing.ps1
arguments: -token $(dn-bot-dnceng-artifact-feeds-rw)
- task: PowerShell@2
displayName: Publish Assets
env:
AZURE_DEVOPS_EXT_PAT: $(dn-bot-dnceng-universal-packages-rw)
inputs:
filePath: eng\common\sdk-task.ps1
arguments: -task PublishArtifactsInManifest -restore -msbuildEngine dotnet

View File

@ -84,10 +84,14 @@ stages:
- task: NuGetAuthenticate@0
displayName: 'Authenticate to AzDO Feeds'
- task: PowerShell@2
displayName: Enable cross-org publishing
inputs:
filePath: eng\common\enable-cross-org-publishing.ps1
arguments: -token $(dn-bot-dnceng-artifact-feeds-rw)
- task: PowerShell@2
displayName: Publish Assets
env:
AZURE_DEVOPS_EXT_PAT: $(dn-bot-dnceng-universal-packages-rw)
inputs:
filePath: eng\common\sdk-task.ps1
arguments: -task PublishArtifactsInManifest -restore -msbuildEngine dotnet

View File

@ -85,10 +85,14 @@ stages:
- task: NuGetAuthenticate@0
displayName: 'Authenticate to AzDO Feeds'
- task: PowerShell@2
displayName: Enable cross-org publishing
inputs:
filePath: eng\common\enable-cross-org-publishing.ps1
arguments: -token $(dn-bot-dnceng-artifact-feeds-rw)
- task: PowerShell@2
displayName: Publish Assets
env:
AZURE_DEVOPS_EXT_PAT: $(dn-bot-dnceng-universal-packages-rw)
inputs:
filePath: eng\common\sdk-task.ps1
arguments: -task PublishArtifactsInManifest -restore -msbuildEngine dotnet

View File

@ -85,10 +85,14 @@ stages:
- task: NuGetAuthenticate@0
displayName: 'Authenticate to AzDO Feeds'
- task: PowerShell@2
displayName: Enable cross-org publishing
inputs:
filePath: eng\common\enable-cross-org-publishing.ps1
arguments: -token $(dn-bot-dnceng-artifact-feeds-rw)
- task: PowerShell@2
displayName: Publish Assets
env:
AZURE_DEVOPS_EXT_PAT: $(dn-bot-dnceng-universal-packages-rw)
inputs:
filePath: eng\common\sdk-task.ps1
arguments: -task PublishArtifactsInManifest -restore -msbuildEngine dotnet

View File

@ -85,10 +85,14 @@ stages:
- task: NuGetAuthenticate@0
displayName: 'Authenticate to AzDO Feeds'
- task: PowerShell@2
displayName: Enable cross-org publishing
inputs:
filePath: eng\common\enable-cross-org-publishing.ps1
arguments: -token $(dn-bot-dnceng-artifact-feeds-rw)
- task: PowerShell@2
displayName: Publish Assets
env:
AZURE_DEVOPS_EXT_PAT: $(dn-bot-dnceng-universal-packages-rw)
inputs:
filePath: eng\common\sdk-task.ps1
arguments: -task PublishArtifactsInManifest -restore -msbuildEngine dotnet

View File

@ -21,7 +21,7 @@ stages:
value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.BARBuildId'] ]
- name: IsStableBuild
value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.IsStableBuild'] ]
condition: contains(dependencies.setupMaestroVars.outputs['setReleaseVars.InitialChannels'], format('[{0}]', variables.PublicValidationRelease_30_Channel_Id))
condition: contains(dependencies.setupMaestroVars.outputs['setReleaseVars.InitialChannels'], format('[{0}]', variables.NetCore_Tools_Validation_Channel_Id))
pool:
vmImage: 'windows-2019'
steps:
@ -50,10 +50,14 @@ stages:
- task: NuGetAuthenticate@0
displayName: 'Authenticate to AzDO Feeds'
- task: PowerShell@2
displayName: Enable cross-org publishing
inputs:
filePath: eng\common\enable-cross-org-publishing.ps1
arguments: -token $(dn-bot-dnceng-artifact-feeds-rw)
- task: PowerShell@2
displayName: Publish Assets
env:
AZURE_DEVOPS_EXT_PAT: $(dn-bot-dnceng-universal-packages-rw)
inputs:
filePath: eng\common\sdk-task.ps1
arguments: -task PublishArtifactsInManifest -restore -msbuildEngine dotnet
@ -88,4 +92,4 @@ stages:
- template: ../../steps/promote-build.yml
parameters:
ChannelId: ${{ variables.PublicValidationRelease_30_Channel_Id }}
ChannelId: ${{ variables.NetCore_Tools_Validation_Channel_Id }}

View File

@ -3,10 +3,6 @@ variables:
- group: DotNet-DotNetCli-Storage
- group: DotNet-MSRC-Storage
# .NET Core 3 Dev
- name: PublicDevRelease_30_Channel_Id
value: 3
# .NET Core 3.1 Dev
- name: PublicDevRelease_31_Channel_Id
value: 128
@ -16,13 +12,21 @@ variables:
value: 131
# .NET Tools - Validation
- name: PublicValidationRelease_30_Channel_Id
- name: NetCore_Tools_Validation_Channel_Id
value: 9
# .NET Tools - Latest
- name: NetCore_Tools_Latest_Channel_Id
value: 2
# .NET 3 Tools - Validation
- name: NETCore_3_Tools_Validation_Channel_Id
value: 390
# .NET 3 Tools - Latest
- name: NetCore_3_Tools_Channel_Id
value: 344
# .NET Core 3.0 Internal Servicing
- name: InternalServicing_30_Channel_Id
value: 184

View File

@ -101,12 +101,6 @@ stages:
artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
- template: \eng\common\templates\post-build\channels\netcore-dev-30.yml
parameters:
symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }}
artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
- template: \eng\common\templates\post-build\channels\netcore-dev-31.yml
parameters:
symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }}
@ -119,11 +113,22 @@ stages:
artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
- template: \eng\common\templates\post-build\channels\public-validation-release.yml
- template: \eng\common\templates\post-build\channels\netcore-tools-validation.yml
parameters:
artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
- template: \eng\common\templates\post-build\channels\netcore-3-tools-validation.yml
parameters:
artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
- template: \eng\common\templates\post-build\channels\netcore-3-tools.yml
parameters:
symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }}
artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
- template: \eng\common\templates\post-build\channels\netcore-release-30.yml
parameters:
symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }}

View File

@ -52,6 +52,7 @@
<_RefSourceOutputPath>$([System.IO.Directory]::GetParent('$(MSBuildProjectDirectory)'))/ref/</_RefSourceOutputPath>
<_RefSourceFileName>$(AssemblyName).$(_RefSourceFileTFM).cs</_RefSourceFileName>
<_ManualRefSourceFileName>$(AssemblyName).Manual.cs</_ManualRefSourceFileName>
<_RefSourceFileOutputPath>$(_RefSourceOutputPath)$(_RefSourceFileName)</_RefSourceFileOutputPath>
</PropertyGroup>
@ -87,10 +88,16 @@
</ItemGroup>
<PropertyGroup>
<_ManualReferenceAssemblyContent />
<_ManualReferenceAssemblyContent Condition="Exists('$(_RefSourceOutputPath)$(_ManualRefSourceFileName)')">
<![CDATA[
<Compile Include="$(_ManualRefSourceFileName)" />]]>
</_ManualReferenceAssemblyContent>
<ReferencesContent>
<![CDATA[
<ItemGroup Condition="'%24(TargetFramework)' == '$(_RefProjectFileTFM)'">
<Compile Include="$(_RefSourceFileName)" />
<Compile Include="$(_RefSourceFileName)" />]]>$(_ManualReferenceAssemblyContent)<![CDATA[
@(FilteredOriginalReferences->'<Reference Include="%(Identity)" />', '%0A ')
</ItemGroup>
]]>

View File

@ -36,7 +36,8 @@
-->
<UseLatestPackageReferences Condition=" '$(UseLatestPackageReferences)' == '' AND '$(IsServicingBuild)' != 'true' ">true</UseLatestPackageReferences>
<UseLatestPackageReferences Condition=" '$(UseLatestPackageReferences)' == '' AND '$(IsImplementationProject)' != 'true' ">true</UseLatestPackageReferences>
<UseLatestPackageReferences Condition=" '$(UseLatestPackageReferences)' == '' AND '$(IsImplementationProject)' == 'true' AND ( '$(IsServicingBuild)' != 'true' OR '$(IsPackable)' == 'true' ) ">true</UseLatestPackageReferences>
<UseLatestPackageReferences
Condition=" '$(UseLatestPackageReferences)' == '' AND '$(IsImplementationProject)' == 'true' AND '$(IsPackable)' == 'true' ">true</UseLatestPackageReferences>
<UseLatestPackageReferences Condition=" '$(UseLatestPackageReferences)' == '' ">false</UseLatestPackageReferences>
<!--
@ -45,7 +46,7 @@
* when a project is a test or sample project
We don't use project references between components in servicing builds between compontents to preserve the baseline as much as possible.
-->
<UseProjectReferences Condition=" '$(UseProjectReferences)' == '' AND '$(IsServicingBuild)' != 'true' ">true</UseProjectReferences>
<UseProjectReferences Condition=" '$(UseProjectReferences)' == '' AND '$(IsServicingBuild)' != 'true' ">true</UseProjectReferences>
<UseProjectReferences Condition=" '$(UseProjectReferences)' == '' AND '$(IsImplementationProject)' != 'true' ">true</UseProjectReferences>
<UseProjectReferences Condition=" '$(UseProjectReferences)' == '' ">false</UseProjectReferences>
@ -122,7 +123,7 @@
Text="Cannot reference &quot;%(_InvalidReferenceToNonSharedFxAssembly.Identity)&quot;. This dependency is not in the shared framework. See docs/SharedFramework.md for instructions on how to modify what is in the shared framework." />
</Target>
<Target Name="_WarnAboutRedundantRef" AfterTargets="ResolveFrameworkReferences">
<Target Name="_WarnAboutRedundantRef" AfterTargets="ResolveFrameworkReferences;ProcessFrameworkReferences">
<Warning Condition="@(FrameworkReference->WithMetadataValue('Identity', 'Microsoft.AspNetCore.App')->Count()) &gt; 1"
Text="Redundant &lt;FrameworkReference&gt;. If you have an explicit item in the project file, you might be able to remove it. Some SDKs, like Microsoft.NET.Sdk.Web, add this implicitly." />
</Target>

View File

@ -3,7 +3,7 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
<StartArguments>-s https://dotnetfeed.blob.core.windows.net/dotnet-core/index.json</StartArguments>
<StartArguments>-s https://api.nuget.org/v3/index.json</StartArguments>
<StartWorkingDirectory>$(MSBuildThisFileDirectory)../../</StartWorkingDirectory>
</PropertyGroup>

View File

@ -12,14 +12,14 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="NuGet.Build.Tasks" Version="5.1.0-rtm.5921" />
<PackageReference Include="NuGet.Build.Tasks" Version="5.3.0-rtm.6192" />
<PackageReference Include="Microsoft.Extensions.DependencyModel" Version="2.1.0" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == '$(DefaultNetCoreTargetFramework)'">
<PackageReference Include="Microsoft.Build.Framework" Version="15.8.166" />
<PackageReference Include="Microsoft.Build.Tasks.Core" Version="15.8.166" />
<PackageReference Include="Microsoft.Build.Utilities.Core" Version="15.8.166" />
<PackageReference Include="Microsoft.Build.Framework" Version="16.3.0" />
<PackageReference Include="Microsoft.Build.Tasks.Core" Version="16.3.0" />
<PackageReference Include="Microsoft.Build.Utilities.Core" Version="16.3.0" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net472'">

View File

@ -25,7 +25,7 @@
},
"msbuild-sdks": {
"Yarn.MSBuild": "1.15.2",
"Microsoft.DotNet.Arcade.Sdk": "1.0.0-beta.19462.4",
"Microsoft.DotNet.Helix.Sdk": "2.0.0-beta.19462.4"
"Microsoft.DotNet.Arcade.Sdk": "1.0.0-beta.19510.3",
"Microsoft.DotNet.Helix.Sdk": "2.0.0-beta.19510.3"
}
}

BIN
packageIcon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

View File

@ -25,6 +25,7 @@
<ItemGroup>
<NuspecProperty Include="OutputBinary=$(OutputPath)$(AssemblyName).dll" />
<NuspecProperty Include="OutputSymbol=$(OutputPath)$(AssemblyName).pdb" />
<NuspecProperty Include="PackageIcon=$(PackageIconFullPath)" />
</ItemGroup>
</Project>

View File

@ -2,10 +2,12 @@
<package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd">
<metadata>
$CommonMetadataElements$
<icon>packageIcon.png</icon>
</metadata>
<files>
<file src="$OutputBinary$" target="analyzers\dotnet\cs\" />
<file src="$OutputSymbol$" target="analyzers\dotnet\cs\" />
<file src="$PackageIcon$" target="" />
</files>
</package>

View File

@ -23,6 +23,7 @@
<NuspecProperty Include="componentsversion=$(ComponentsPackageVersion)" />
<NuspecProperty Include="razorversion=$(MicrosoftAspNetCoreRazorDesignPackageVersion)" />
<NuspecProperty Include="blazormonoversion=$(MicrosoftAspNetCoreBlazorMonoPackageVersion)" />
<NuspecProperty Include="PackageIcon=$(PackageIconFullPath)" />
</ItemGroup>
<ItemGroup>

View File

@ -5,6 +5,7 @@
<dependencies>
<dependency id="Microsoft.AspNetCore.Blazor.Mono" version="$blazormonoversion$" include="all" />
</dependencies>
<icon>packageIcon.png</icon>
</metadata>
<files>
<file src="..\..\..\THIRD-PARTY-NOTICES.txt" />
@ -12,5 +13,6 @@
<file src="targets\**" target="targets" />
<file src="$publishdir$**\*" target="tools/" />
<file src="..\..\..\Web.JS\dist\$configuration$\blazor.*.js" target="tools/blazor" />
<file src="$PackageIcon$" target="" />
</files>
</package>

View File

@ -33,6 +33,7 @@
<NuspecProperty Include="publishDir=$(PublishDir)" />
<NuspecProperty Include="componentsrootdir=..\..\..\" />
<NuspecProperty Include="blazorversion=$(PackageVersion)" />
<NuspecProperty Include="PackageIcon=$(PackageIconFullPath)" />
</ItemGroup>
</Project>

View File

@ -2,10 +2,12 @@
<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
<metadata>
$CommonMetadataElements$
<icon>packageIcon.png</icon>
</metadata>
<files>
<file src="build\**" target="build" />
<file src="$publishDir$**\*" target="tools" />
<file src="$componentsrootdir$THIRD-PARTY-NOTICES.txt" target=".\THIRD-PARTY-NOTICES.txt" />
<file src="$PackageIcon$" target="" />
</files>
</package>

View File

@ -15,6 +15,10 @@
<IsProjectReferenceProvider>false</IsProjectReferenceProvider>
</PropertyGroup>
<ItemGroup>
<NuspecProperty Include="PackageIcon=$(PackageIconFullPath)" />
</ItemGroup>
<ItemGroup>
<UpToDateCheckInput Include="content\**\.template.config.src\**\*.*" />
</ItemGroup>

View File

@ -5,11 +5,13 @@
<packageTypes>
<packageType name="Template" />
</packageTypes>
<icon>packageIcon.png</icon>
</metadata>
<files>
<file
src="content/**"
exclude="**/bin/**;**/obj/**;**/.template.config.src/**;content/Directory.Build.props;content/Directory.Build.targets;"
target="Content" />
<file src="$PackageIcon$" target="" />
</files>
</package>

View File

@ -96,6 +96,25 @@ app {
color: red;
}
#blazor-error-ui {
background: lightyellow;
bottom: 0;
box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
display: none;
left: 0;
padding: 0.6rem 1.25rem 0.7rem 1.25rem;
position: fixed;
width: 100%;
z-index: 1000;
}
#blazor-error-ui .dismiss {
cursor: pointer;
position: absolute;
right: 0.75rem;
top: 0.5rem;
}
@media (max-width: 767.98px) {
.main .top-row {
display: none;

View File

@ -1,5 +1,6 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
@ -8,9 +9,16 @@
<link href="css/bootstrap/bootstrap.min.css" rel="stylesheet" />
<link href="css/site.css" rel="stylesheet" />
</head>
<body>
<app>Loading...</app>
<div id="blazor-error-ui">
An unhandled error has occurred.
<a href class="reload">Reload</a>
<a class="dismiss">🗙</a>
</div>
<script src="_framework/blazor.webassembly.js"></script>
</body>
</html>

View File

@ -23,6 +23,14 @@
<Reference Include="System.Buffers" />
</ItemGroup>
<!-- These references were removed in 3.0 -->
<ItemGroup>
<SuppressBaselineReference Include="Microsoft.AspNetCore.Components.Analyzers" />
<SuppressBaselineReference Include="Microsoft.AspNetCore.Authorization" />
<SuppressBaselineReference Include="Microsoft.JSInterop" />
<SuppressBaselineReference Include="System.ComponentModel.Annotations" />
</ItemGroup>
<Target Name="_GetNuspecDependencyPackageVersions">
<MSBuild Targets="_GetPackageVersionInfo"
BuildInParallel="$(BuildInParallel)"
@ -47,6 +55,7 @@
<NuspecProperty Condition="'$(DotNetBuildFromSource)' != 'true'" Include="systemComponentModelAnnotationsPackageVersion=$(SystemComponentModelAnnotationsPackageVersion)" />
<NuspecProperty Include="AssemblyName=$(AssemblyName)" />
<NuspecProperty Include="OutputPath=$(OutputPath)" />
<NuspecProperty Include="PackageIcon=$(PackageIconFullPath)" />
</ItemGroup>
</Project>

View File

@ -15,11 +15,13 @@
<dependency id="Microsoft.JSInterop" version="$jsInteropPackageVersion$" exclude="Build,Analyzers" />
</group>
</dependencies>
<icon>packageIcon.png</icon>
</metadata>
<files>
<file src="$OutputPath$**\$AssemblyName$.dll" target="lib\" />
<file src="$OutputPath$**\$AssemblyName$.pdb" target="lib\" />
<file src="$OutputPath$**\$AssemblyName$.xml" target="lib\" />
<file src="$PackageIcon$" target="" />
<file src="..\..\THIRD-PARTY-NOTICES.txt" target=".\THIRD-PARTY-NOTICES.txt" />
</files>
</package>

View File

@ -9,11 +9,13 @@
<dependency id="Microsoft.JSInterop" version="$jsInteropPackageVersion$" exclude="Build,Analyzers" />
</group>
</dependencies>
<icon>packageIcon.png</icon>
</metadata>
<files>
<file src="$OutputPath$**\$AssemblyName$.dll" target="lib\" />
<file src="$OutputPath$**\$AssemblyName$.pdb" target="lib\" />
<file src="$OutputPath$**\$AssemblyName$.xml" target="lib\" />
<file src="$PackageIcon$" target="" />
<file src="..\..\THIRD-PARTY-NOTICES.txt" target=".\THIRD-PARTY-NOTICES.txt" />
</files>
</package>

View File

@ -1,7 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
<!-- Intentionally targeting netcoreapp3.0 because we do not want to update the Benchmark client to use 3.1 -->
<TargetFramework>netcoreapp3.0</TargetFramework>
<IsPackable>true</IsPackable>
<IsShippingPackage>false</IsShippingPackage>
<HasReferenceAssembly>false</HasReferenceAssembly>

View File

@ -1,4 +1,4 @@
@page "/"
@page "/"
<h1>Hello, world!</h1>

View File

@ -13,10 +13,16 @@
<link href="css/site.css" rel="stylesheet" />
</head>
<body>
<app>
@(await Html.RenderComponentAsync<App>(RenderMode.ServerPrerendered))
</app>
<app><component type="typeof(App)" render-mode="ServerPrerendered" /></app>
<script src="_framework/blazor.server.js"></script>
<script src="_framework/blazor.server.js" autostart="false"></script>
<script>
(function start() {
Blazor.start({
logLevel: 1, // LogLevel.Debug
configureSignalR: builder => builder.configureLogging("debug") // LogLevel.Debug
});
})()
</script>
</body>
</html>

View File

@ -1,4 +1,4 @@
@inherits LayoutComponentBase
@inherits LayoutComponentBase
<div class="sidebar">
<NavMenu />
@ -12,4 +12,10 @@
<div class="content px-4">
@Body
</div>
</div>
<div id="blazor-error-ui">
An unhandled error has occurred.
<a class="reload">Reload</a>
<a class="dismiss">X</a>
</div>

View File

@ -1,4 +1,4 @@
<div class="top-row pl-4 navbar navbar-dark">
<div class="top-row pl-4 navbar navbar-dark">
<a class="navbar-brand" href="">BlazorServerApp</a>
<button class="navbar-toggler" @onclick="ToggleNavMenu">
<span class="navbar-toggler-icon"></span>

View File

@ -1,9 +1,10 @@
{
"detailedErrors": true,
"Logging": {
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
"Microsoft": "Debug"
}
}
}

View File

@ -9,9 +9,9 @@ a, .btn-link {
}
.btn-primary {
color: #fff;
background-color: #1b6ec2;
border-color: #1861ac;
color: #fff;
background-color: #1b6ec2;
border-color: #1861ac;
}
app {
@ -111,6 +111,25 @@ app {
color: red;
}
#blazor-error-ui {
background: lightyellow;
bottom: 0;
box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
display: none;
left: 0;
padding: 0.6rem 1.25rem 0.7rem 1.25rem;
position: fixed;
width: 100%;
z-index: 1000;
}
#blazor-error-ui .dismiss {
cursor: pointer;
position: absolute;
right: 0.75rem;
top: 0.5rem;
}
@media (max-width: 767.98px) {
.main .top-row {
display: none;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -2,6 +2,7 @@ import '@dotnet/jsinterop';
import './GlobalExports';
import * as signalR from '@aspnet/signalr';
import { MessagePackHubProtocol } from '@aspnet/signalr-protocol-msgpack';
import { showErrorNotification } from './BootErrors';
import { shouldAutoStart } from './BootCommon';
import { RenderQueue } from './Platform/Circuits/RenderQueue';
import { ConsoleLogger } from './Platform/Logging/Loggers';
@ -106,6 +107,7 @@ async function initializeConnection(options: BlazorOptions, logger: Logger, circ
connection.on('JS.Error', error => {
renderingFailed = true;
unhandledError(connection, error, logger);
showErrorNotification();
});
window['Blazor']._internal.forceCloseConnection = () => connection.stop();

View File

@ -0,0 +1,30 @@
let hasFailed = false;
export async function showErrorNotification() {
let errorUi = document.querySelector('#blazor-error-ui') as HTMLElement;
if (errorUi) {
errorUi.style.display = 'block';
}
if (!hasFailed) {
hasFailed = true;
const errorUiReloads = document.querySelectorAll<HTMLElement>('#blazor-error-ui .reload');
errorUiReloads.forEach(reload => {
reload.onclick = function (e) {
location.reload();
e.preventDefault();
};
});
let errorUiDismiss = document.querySelectorAll<HTMLElement>('#blazor-error-ui .dismiss');
errorUiDismiss.forEach(dismiss => {
dismiss.onclick = function (e) {
const errorUi = document.querySelector<HTMLElement>('#blazor-error-ui');
if (errorUi) {
errorUi.style.display = 'none';
}
e.preventDefault();
};
});
}
}

View File

@ -101,7 +101,7 @@ export function discoverComponents(document: Document): ComponentDescriptor[] {
discoveredComponents.push(entry);
}
return discoveredComponents;
return discoveredComponents.sort((a, b) => a.sequence - b.sequence);
}

View File

@ -1,6 +1,7 @@
import { MethodHandle, System_Object, System_String, System_Array, Pointer, Platform } from '../Platform';
import { getFileNameFromUrl } from '../Url';
import { attachDebuggerHotkey, hasDebuggingEnabled } from './MonoDebugger';
import { showErrorNotification } from '../../BootErrors';
const assemblyHandleCache: { [assemblyName: string]: number } = {};
const typeHandleCache: { [fullyQualifiedTypeName: string]: number } = {};
@ -232,7 +233,11 @@ function createEmscriptenModuleInstance(loadAssemblyUrls: string[], onReady: ()
const suppressMessages = ['DEBUGGING ENABLED'];
module.print = line => (suppressMessages.indexOf(line) < 0 && console.log(`WASM: ${line}`));
module.printErr = line => console.error(`WASM: ${line}`);
module.printErr = line => {
console.error(`WASM: ${line}`);
showErrorNotification();
};
module.preRun = [];
module.postRun = [];
module.preloadPlugins = [];

View File

@ -341,9 +341,18 @@ export class BrowserRenderer {
}
}
private tryApplyValueProperty(batch: RenderBatch, element: Element, attributeFrame: RenderTreeFrame | null) {
private tryApplyValueProperty(batch: RenderBatch, element: Element, attributeFrame: RenderTreeFrame | null): boolean {
// Certain elements have built-in behaviour for their 'value' property
const frameReader = batch.frameReader;
if (element.tagName === 'INPUT' && element.getAttribute('type') === 'time' && !element.getAttribute('step')) {
const timeValue = attributeFrame ? frameReader.attributeValue(attributeFrame) : null;
if (timeValue) {
element['value'] = timeValue.substring(0, 5);
return true;
}
}
switch (element.tagName) {
case 'INPUT':
case 'SELECT':

View File

@ -1,13 +1,19 @@
export class EventForDotNet<TData extends UIEventArgs> {
constructor(public readonly type: EventArgsType, public readonly data: TData) {
public constructor(public readonly type: EventArgsType, public readonly data: TData) {
}
static fromDOMEvent(event: Event): EventForDotNet<UIEventArgs> {
public static fromDOMEvent(event: Event): EventForDotNet<UIEventArgs> {
const element = event.target as Element;
switch (event.type) {
case 'input':
case 'change': {
if (isTimeBasedInput(element)) {
const normalizedValue = normalizeTimeBasedValue(element);
return new EventForDotNet<UIChangeEventArgs>('change', { type: event.type, value: normalizedValue });
}
const targetIsCheckbox = isCheckbox(element);
const newValue = targetIsCheckbox ? !!element['checked'] : element['value'];
return new EventForDotNet<UIChangeEventArgs>('change', { type: event.type, value: newValue });
@ -36,7 +42,7 @@ export class EventForDotNet<TData extends UIEventArgs> {
case 'keydown':
case 'keyup':
case 'keypress':
return new EventForDotNet<UIKeyboardEventArgs>('keyboard', parseKeyboardEvent(<KeyboardEvent>event));
return new EventForDotNet<UIKeyboardEventArgs>('keyboard', parseKeyboardEvent(event as KeyboardEvent));
case 'contextmenu':
case 'click':
@ -46,10 +52,10 @@ export class EventForDotNet<TData extends UIEventArgs> {
case 'mousedown':
case 'mouseup':
case 'dblclick':
return new EventForDotNet<UIMouseEventArgs>('mouse', parseMouseEvent(<MouseEvent>event));
return new EventForDotNet<UIMouseEventArgs>('mouse', parseMouseEvent(event as MouseEvent));
case 'error':
return new EventForDotNet<UIErrorEventArgs>('error', parseErrorEvent(<ErrorEvent>event));
return new EventForDotNet<UIErrorEventArgs>('error', parseErrorEvent(event as ErrorEvent));
case 'loadstart':
case 'timeout':
@ -57,7 +63,7 @@ export class EventForDotNet<TData extends UIEventArgs> {
case 'load':
case 'loadend':
case 'progress':
return new EventForDotNet<UIProgressEventArgs>('progress', parseProgressEvent(<ProgressEvent>event));
return new EventForDotNet<UIProgressEventArgs>('progress', parseProgressEvent(event as ProgressEvent));
case 'touchcancel':
case 'touchend':
@ -65,7 +71,7 @@ export class EventForDotNet<TData extends UIEventArgs> {
case 'touchenter':
case 'touchleave':
case 'touchstart':
return new EventForDotNet<UITouchEventArgs>('touch', parseTouchEvent(<TouchEvent>event));
return new EventForDotNet<UITouchEventArgs>('touch', parseTouchEvent(event as TouchEvent));
case 'gotpointercapture':
case 'lostpointercapture':
@ -77,11 +83,11 @@ export class EventForDotNet<TData extends UIEventArgs> {
case 'pointerout':
case 'pointerover':
case 'pointerup':
return new EventForDotNet<UIPointerEventArgs>('pointer', parsePointerEvent(<PointerEvent>event));
return new EventForDotNet<UIPointerEventArgs>('pointer', parsePointerEvent(event as PointerEvent));
case 'wheel':
case 'mousewheel':
return new EventForDotNet<UIWheelEventArgs>('wheel', parseWheelEvent(<WheelEvent>event));
return new EventForDotNet<UIWheelEventArgs>('wheel', parseWheelEvent(event as WheelEvent));
default:
return new EventForDotNet<UIEventArgs>('unknown', { type: event.type });
@ -204,8 +210,38 @@ function parseMouseEvent(event: MouseEvent) {
};
}
function isCheckbox(element: Element | null) {
return element && element.tagName === 'INPUT' && element.getAttribute('type') === 'checkbox';
function isCheckbox(element: Element | null): boolean {
return !!element && element.tagName === 'INPUT' && element.getAttribute('type') === 'checkbox';
}
const timeBasedInputs = [
'date',
'datetime-local',
'month',
'time',
'week',
];
function isTimeBasedInput(element: Element): element is HTMLInputElement {
return timeBasedInputs.indexOf(element.getAttribute('type')!) !== -1;
}
function normalizeTimeBasedValue(element: HTMLInputElement): string {
const value = element.value;
const type = element.type;
switch (type) {
case 'date':
case 'datetime-local':
case 'month':
return value;
case 'time':
return value.length === 5 ? value + ':00' : value; // Convert hh:mm to hh:mm:00
case 'week':
// For now we are not going to normalize input type week as it is not trivial
return value;
}
throw new Error(`Invalid element type '${type}'.`);
}
// The following interfaces must be kept in sync with the UIEventArgs C# classes

View File

@ -42,7 +42,7 @@ namespace Microsoft.AspNetCore.Components.Forms
protected override void BuildRenderTree(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder builder) { }
protected override void OnParametersSet() { }
}
public abstract partial class InputBase<TValue> : Microsoft.AspNetCore.Components.ComponentBase
public abstract partial class InputBase<TValue> : Microsoft.AspNetCore.Components.ComponentBase, System.IDisposable
{
protected InputBase() { }
[Microsoft.AspNetCore.Components.ParameterAttribute(CaptureUnmatchedValues=true)]
@ -58,8 +58,10 @@ namespace Microsoft.AspNetCore.Components.Forms
public Microsoft.AspNetCore.Components.EventCallback<TValue> ValueChanged { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
[Microsoft.AspNetCore.Components.ParameterAttribute]
public System.Linq.Expressions.Expression<System.Func<TValue>> ValueExpression { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
protected virtual void Dispose(bool disposing) { }
protected virtual string FormatValueAsString(TValue value) { throw null; }
public override System.Threading.Tasks.Task SetParametersAsync(Microsoft.AspNetCore.Components.ParameterView parameters) { throw null; }
void System.IDisposable.Dispose() { }
protected abstract bool TryParseValueFromString(string value, out TValue result, out string validationErrorMessage);
}
public partial class InputCheckbox : Microsoft.AspNetCore.Components.Forms.InputBase<bool>
@ -172,9 +174,15 @@ namespace Microsoft.AspNetCore.Components.Web
[Microsoft.AspNetCore.Components.BindInputElementAttribute("checkbox", null, "checked", "onchange", false, null)]
[Microsoft.AspNetCore.Components.BindInputElementAttribute("date", "value", "value", "onchange", true, "yyyy-MM-dd")]
[Microsoft.AspNetCore.Components.BindInputElementAttribute("date", null, "value", "onchange", true, "yyyy-MM-dd")]
[Microsoft.AspNetCore.Components.BindInputElementAttribute("datetime-local", "value", "value", "onchange", true, "yyyy-MM-ddTHH:mm:ss")]
[Microsoft.AspNetCore.Components.BindInputElementAttribute("datetime-local", null, "value", "onchange", true, "yyyy-MM-ddTHH:mm:ss")]
[Microsoft.AspNetCore.Components.BindInputElementAttribute("month", "value", "value", "onchange", true, "yyyy-MM")]
[Microsoft.AspNetCore.Components.BindInputElementAttribute("month", null, "value", "onchange", true, "yyyy-MM")]
[Microsoft.AspNetCore.Components.BindInputElementAttribute("number", "value", "value", "onchange", true, null)]
[Microsoft.AspNetCore.Components.BindInputElementAttribute("number", null, "value", "onchange", true, null)]
[Microsoft.AspNetCore.Components.BindInputElementAttribute("text", null, "value", "onchange", false, null)]
[Microsoft.AspNetCore.Components.BindInputElementAttribute("time", "value", "value", "onchange", true, "HH:mm:ss")]
[Microsoft.AspNetCore.Components.BindInputElementAttribute("time", null, "value", "onchange", true, "HH:mm:ss")]
[Microsoft.AspNetCore.Components.BindInputElementAttribute(null, "value", "value", "onchange", false, null)]
[Microsoft.AspNetCore.Components.BindInputElementAttribute(null, null, "value", "onchange", false, null)]
public static partial class BindAttributes

View File

@ -42,7 +42,7 @@ namespace Microsoft.AspNetCore.Components.Forms
protected override void BuildRenderTree(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder builder) { }
protected override void OnParametersSet() { }
}
public abstract partial class InputBase<TValue> : Microsoft.AspNetCore.Components.ComponentBase
public abstract partial class InputBase<TValue> : Microsoft.AspNetCore.Components.ComponentBase, System.IDisposable
{
protected InputBase() { }
[Microsoft.AspNetCore.Components.ParameterAttribute(CaptureUnmatchedValues=true)]
@ -58,8 +58,10 @@ namespace Microsoft.AspNetCore.Components.Forms
public Microsoft.AspNetCore.Components.EventCallback<TValue> ValueChanged { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
[Microsoft.AspNetCore.Components.ParameterAttribute]
public System.Linq.Expressions.Expression<System.Func<TValue>> ValueExpression { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
protected virtual void Dispose(bool disposing) { }
protected virtual string FormatValueAsString(TValue value) { throw null; }
public override System.Threading.Tasks.Task SetParametersAsync(Microsoft.AspNetCore.Components.ParameterView parameters) { throw null; }
void System.IDisposable.Dispose() { }
protected abstract bool TryParseValueFromString(string value, out TValue result, out string validationErrorMessage);
}
public partial class InputCheckbox : Microsoft.AspNetCore.Components.Forms.InputBase<bool>
@ -172,9 +174,15 @@ namespace Microsoft.AspNetCore.Components.Web
[Microsoft.AspNetCore.Components.BindInputElementAttribute("checkbox", null, "checked", "onchange", false, null)]
[Microsoft.AspNetCore.Components.BindInputElementAttribute("date", "value", "value", "onchange", true, "yyyy-MM-dd")]
[Microsoft.AspNetCore.Components.BindInputElementAttribute("date", null, "value", "onchange", true, "yyyy-MM-dd")]
[Microsoft.AspNetCore.Components.BindInputElementAttribute("datetime-local", "value", "value", "onchange", true, "yyyy-MM-ddTHH:mm:ss")]
[Microsoft.AspNetCore.Components.BindInputElementAttribute("datetime-local", null, "value", "onchange", true, "yyyy-MM-ddTHH:mm:ss")]
[Microsoft.AspNetCore.Components.BindInputElementAttribute("month", "value", "value", "onchange", true, "yyyy-MM")]
[Microsoft.AspNetCore.Components.BindInputElementAttribute("month", null, "value", "onchange", true, "yyyy-MM")]
[Microsoft.AspNetCore.Components.BindInputElementAttribute("number", "value", "value", "onchange", true, null)]
[Microsoft.AspNetCore.Components.BindInputElementAttribute("number", null, "value", "onchange", true, null)]
[Microsoft.AspNetCore.Components.BindInputElementAttribute("text", null, "value", "onchange", false, null)]
[Microsoft.AspNetCore.Components.BindInputElementAttribute("time", "value", "value", "onchange", true, "HH:mm:ss")]
[Microsoft.AspNetCore.Components.BindInputElementAttribute("time", null, "value", "onchange", true, "HH:mm:ss")]
[Microsoft.AspNetCore.Components.BindInputElementAttribute(null, "value", "value", "onchange", false, null)]
[Microsoft.AspNetCore.Components.BindInputElementAttribute(null, null, "value", "onchange", false, null)]
public static partial class BindAttributes

View File

@ -13,8 +13,9 @@ namespace Microsoft.AspNetCore.Components.Forms
/// integrates with an <see cref="Forms.EditContext"/>, which must be supplied
/// as a cascading parameter.
/// </summary>
public abstract class InputBase<TValue> : ComponentBase
public abstract class InputBase<TValue> : ComponentBase, IDisposable
{
private readonly EventHandler<ValidationStateChangedEventArgs> _validationStateChangedHandler;
private bool _previousParsingAttemptFailed;
private ValidationMessageStore _parsingValidationMessages;
private Type _nullableUnderlyingType;
@ -122,7 +123,15 @@ namespace Microsoft.AspNetCore.Components.Forms
}
/// <summary>
/// Formats the value as a string. Derived classes can override this to determine the formatting used for <see cref="CurrentValueAsString"/>.
/// Constructs an instance of <see cref="InputBase{TValue}"/>.
/// </summary>
protected InputBase()
{
_validationStateChangedHandler = (sender, eventArgs) => StateHasChanged();
}
/// <summary>
/// Formats the value as a string. Derived classes can override this to determine the formating used for <see cref="CurrentValueAsString"/>.
/// </summary>
/// <param name="value">The value to format.</param>
/// <returns>A string representation of the value.</returns>
@ -193,6 +202,8 @@ namespace Microsoft.AspNetCore.Components.Forms
EditContext = CascadedEditContext;
FieldIdentifier = FieldIdentifier.Create(ValueExpression);
_nullableUnderlyingType = Nullable.GetUnderlyingType(typeof(TValue));
EditContext.OnValidationStateChanged += _validationStateChangedHandler;
}
else if (CascadedEditContext != EditContext)
{
@ -208,5 +219,19 @@ namespace Microsoft.AspNetCore.Components.Forms
// For derived components, retain the usual lifecycle with OnInit/OnParametersSet/etc.
return base.SetParametersAsync(ParameterView.Empty);
}
protected virtual void Dispose(bool disposing)
{
}
void IDisposable.Dispose()
{
if (EditContext != null)
{
EditContext.OnValidationStateChanged -= _validationStateChangedHandler;
}
Dispose(disposing: true);
}
}
}

View File

@ -21,6 +21,7 @@ namespace Microsoft.AspNetCore.Components.Forms
// of it for us. We will only get asked to parse the T for nonempty inputs.
var targetType = Nullable.GetUnderlyingType(typeof(TValue)) ?? typeof(TValue);
if (targetType == typeof(int) ||
targetType == typeof(long) ||
targetType == typeof(float) ||
targetType == typeof(double) ||
targetType == typeof(decimal))

View File

@ -175,7 +175,7 @@ namespace Microsoft.AspNetCore.Components.Routing
var prefixLength = prefix.Length;
if (value.Length > prefixLength)
{
return value.StartsWith(prefix, StringComparison.Ordinal)
return value.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)
&& (
// Only match when there's a separator character either at the end of the
// prefix or right after it.

View File

@ -30,6 +30,20 @@ namespace Microsoft.AspNetCore.Components.Web
[BindInputElement("date", null, "value", "onchange", isInvariantCulture: true, format: "yyyy-MM-dd")]
[BindInputElement("date", "value", "value", "onchange", isInvariantCulture: true, format: "yyyy-MM-dd")]
// type="datetime-local" is invariant culture with a specific format.
// See https://docs.microsoft.com/en-us/dotnet/standard/base-types/standard-date-and-time-format-strings for details.
[BindInputElement("datetime-local", null, "value", "onchange", isInvariantCulture: true, format: "yyyy-MM-ddTHH:mm:ss")]
[BindInputElement("datetime-local", "value", "value", "onchange", isInvariantCulture: true, format: "yyyy-MM-ddTHH:mm:ss")]
// type="month" is invariant culture with a specific format.
// See https://docs.microsoft.com/en-us/dotnet/standard/base-types/standard-date-and-time-format-strings for details.
[BindInputElement("month", null, "value", "onchange", isInvariantCulture: true, format: "yyyy-MM")]
[BindInputElement("month", "value", "value", "onchange", isInvariantCulture: true, format: "yyyy-MM")]
// type="time" is invariant culture with a specific format.
[BindInputElement("time", null, "value", "onchange", isInvariantCulture: true, format: "HH:mm:ss")]
[BindInputElement("time", "value", "value", "onchange", isInvariantCulture: true, format: "HH:mm:ss")]
[BindElement("select", null, "value", "onchange")]
[BindElement("textarea", null, "value", "onchange")]
public static class BindAttributes

View File

@ -294,7 +294,7 @@ namespace Microsoft.AspNetCore.Components.Forms
rootComponent.EditContext.OnValidationStateChanged += (sender, eventArgs) => { numValidationStateChanges++; };
// Act
inputComponent.CurrentValueAsString = "1991/11/20";
await inputComponent.SetCurrentValueAsStringAsync("1991/11/20");
// Assert
var receivedParsedValue = valueChangedArgs.Single();
@ -324,14 +324,14 @@ namespace Microsoft.AspNetCore.Components.Forms
rootComponent.EditContext.OnValidationStateChanged += (sender, eventArgs) => { numValidationStateChanges++; };
// Act/Assert 1: Transition to invalid
inputComponent.CurrentValueAsString = "1991/11/40";
await inputComponent.SetCurrentValueAsStringAsync("1991/11/40");
Assert.Empty(valueChangedArgs);
Assert.True(rootComponent.EditContext.IsModified(fieldIdentifier));
Assert.Equal(new[] { "Bad date value" }, rootComponent.EditContext.GetValidationMessages(fieldIdentifier));
Assert.Equal(1, numValidationStateChanges);
// Act/Assert 2: Transition to valid
inputComponent.CurrentValueAsString = "1991/11/20";
await inputComponent.SetCurrentValueAsStringAsync("1991/11/20");
var receivedParsedValue = valueChangedArgs.Single();
Assert.Equal(1991, receivedParsedValue.Year);
Assert.Equal(11, receivedParsedValue.Month);
@ -341,6 +341,65 @@ namespace Microsoft.AspNetCore.Components.Forms
Assert.Equal(2, numValidationStateChanges);
}
[Fact]
public async Task RespondsToValidationStateChangeNotifications()
{
// Arrange
var model = new TestModel();
var rootComponent = new TestInputHostComponent<string, TestInputComponent<string>>
{
EditContext = new EditContext(model),
ValueExpression = () => model.StringProperty
};
var fieldIdentifier = FieldIdentifier.Create(() => model.StringProperty);
var renderer = new TestRenderer();
var rootComponentId = renderer.AssignRootComponentId(rootComponent);
await renderer.RenderRootComponentAsync(rootComponentId);
// Initally, it rendered one batch and is valid
var batch1 = renderer.Batches.Single();
var componentFrame1 = batch1.GetComponentFrames<TestInputComponent<string>>().Single();
var inputComponentId = componentFrame1.ComponentId;
var component = (TestInputComponent<string>)componentFrame1.Component;
Assert.Equal("valid", component.CssClass);
// Act: update the field state in the EditContext and notify
var messageStore = new ValidationMessageStore(rootComponent.EditContext);
messageStore.Add(fieldIdentifier, "Some message");
await renderer.Dispatcher.InvokeAsync(rootComponent.EditContext.NotifyValidationStateChanged);
// Assert: The input component rendered itself again and now has the new class
var batch2 = renderer.Batches.Skip(1).Single();
Assert.Equal(inputComponentId, batch2.DiffsByComponentId.Keys.Single());
Assert.Equal("invalid", component.CssClass);
}
[Fact]
public async Task UnsubscribesFromValidationStateChangeNotifications()
{
// Arrange
var model = new TestModel();
var rootComponent = new TestInputHostComponent<string, TestInputComponent<string>>
{
EditContext = new EditContext(model),
ValueExpression = () => model.StringProperty
};
var fieldIdentifier = FieldIdentifier.Create(() => model.StringProperty);
var renderer = new TestRenderer();
var rootComponentId = renderer.AssignRootComponentId(rootComponent);
await renderer.RenderRootComponentAsync(rootComponentId);
var component = renderer.Batches.Single().GetComponentFrames<TestInputComponent<string>>().Single().Component;
// Act: dispose, then update the field state in the EditContext and notify
((IDisposable)component).Dispose();
var messageStore = new ValidationMessageStore(rootComponent.EditContext);
messageStore.Add(fieldIdentifier, "Some message");
await renderer.Dispatcher.InvokeAsync(rootComponent.EditContext.NotifyValidationStateChanged);
// Assert: No additional render
Assert.Empty(renderer.Batches.Skip(1));
}
private static TComponent FindComponent<TComponent>(CapturedBatch batch)
=> batch.ReferenceFrames
.Where(f => f.FrameType == RenderTreeFrameType.Component)
@ -376,7 +435,6 @@ namespace Microsoft.AspNetCore.Components.Forms
public new string CurrentValueAsString
{
get => base.CurrentValueAsString;
set { base.CurrentValueAsString = value; }
}
public new IReadOnlyDictionary<string, object> AdditionalAttributes => base.AdditionalAttributes;
@ -391,6 +449,15 @@ namespace Microsoft.AspNetCore.Components.Forms
{
throw new NotImplementedException();
}
public async Task SetCurrentValueAsStringAsync(string value)
{
// This is equivalent to the subclass writing to CurrentValueAsString
// (e.g., from @bind), except to simplify the test code there's an InvokeAsync
// here. In production code it wouldn't normally be required because @bind
// calls run on the sync context anyway.
await InvokeAsync(() => { base.CurrentValueAsString = value; });
}
}
class TestDateInputComponent : TestInputComponent<DateTime>

View File

@ -0,0 +1,60 @@
// 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.Text.Json;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components.E2ETest.Infrastructure;
using Microsoft.AspNetCore.Components.E2ETest.Infrastructure.ServerFixtures;
using Microsoft.AspNetCore.E2ETesting;
using OpenQA.Selenium;
using TestServer;
using Xunit;
using Xunit.Abstractions;
namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests
{
public class ComponentWithParametersTest : ServerTestBase<BasicTestAppServerSiteFixture<PrerenderedStartup>>
{
public ComponentWithParametersTest(
BrowserFixture browserFixture,
BasicTestAppServerSiteFixture<PrerenderedStartup> serverFixture,
ITestOutputHelper output)
: base(browserFixture, serverFixture, output)
{
}
[Fact]
public void PassingParametersToComponentsFromThePageWorks()
{
Navigate("/prerendered/componentwithparameters?QueryValue=testQueryValue");
BeginInteractivity();
Browser.Exists(By.CssSelector(".interactive"));
var parameter1 = Browser.FindElement(By.CssSelector(".Param1"));
Assert.Equal(100, parameter1.FindElements(By.CssSelector("li")).Count);
Assert.Equal("99 99", parameter1.FindElement(By.CssSelector("li:last-child")).Text);
// The assigned value is of a more derived type than the declared model type. This check
// verifies we use the actual model type during round tripping.
var parameter2 = Browser.FindElement(By.CssSelector(".Param2"));
Assert.Equal("Value Derived-Value", parameter2.Text);
// This check verifies CaptureUnmatchedValues works
var parameter3 = Browser.FindElements(By.CssSelector(".Param3 li"));
Assert.Collection(
parameter3,
p => Assert.Equal("key1 testQueryValue", p.Text),
p => Assert.Equal("key2 43", p.Text));
}
private void BeginInteractivity()
{
Browser.FindElement(By.Id("load-boot-script")).Click();
}
}
}

View File

@ -174,6 +174,18 @@ namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests
Browser.Equal(9000.ToString(cultureInfo), () => display.Text);
Browser.Equal(9000.ToString(CultureInfo.InvariantCulture), () => input.GetAttribute("value"));
// long
input = Browser.FindElement(By.Id("inputnumber_long"));
display = Browser.FindElement(By.Id("inputnumber_long_value"));
Browser.Equal(4200.ToString(cultureInfo), () => display.Text);
Browser.Equal(4200.ToString(CultureInfo.InvariantCulture), () => input.GetAttribute("value"));
input.Clear();
input.SendKeys(90000000000.ToString(CultureInfo.InvariantCulture));
input.SendKeys("\t");
Browser.Equal(90000000000.ToString(cultureInfo), () => display.Text);
Browser.Equal(90000000000.ToString(CultureInfo.InvariantCulture), () => input.GetAttribute("value"));
// decimal
input = Browser.FindElement(By.Id("inputnumber_decimal"));
display = Browser.FindElement(By.Id("inputnumber_decimal_value"));

View File

@ -16,13 +16,13 @@ using Xunit.Abstractions;
namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests
{
public class MultipleComponentsTest : ServerTestBase<BasicTestAppServerSiteFixture<PrerenderedStartup>>
public class MultipleComponentsTest : ServerTestBase<BasicTestAppServerSiteFixture<MultipleComponents>>
{
private const string MarkerPattern = ".*?<!--Blazor:(.*?)-->.*?";
public MultipleComponentsTest(
BrowserFixture browserFixture,
BasicTestAppServerSiteFixture<PrerenderedStartup> serverFixture,
BasicTestAppServerSiteFixture<MultipleComponents> serverFixture,
ITestOutputHelper output)
: base(browserFixture, serverFixture, output)
{
@ -46,7 +46,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests
[Fact]
public void DoesNotStartMultipleConnections()
{
Navigate("/prerendered/multiple-components");
Navigate("/multiple-components");
BeginInteractivity();
Browser.Exists(By.CssSelector("h3.interactive"));
@ -60,17 +60,18 @@ namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests
});
}
[Fact]
public void CanRenderMultipleRootComponents()
{
Navigate("/prerendered/multiple-components");
Navigate("/multiple-components");
var greets = Browser.FindElements(By.CssSelector(".greet-wrapper .greet")).Select(e => e.Text).ToArray();
Assert.Equal(5, greets.Length); // 1 statically rendered + 3 prerendered + 1 server prerendered
Assert.Equal(7, greets.Length); // 1 statically rendered + 5 prerendered + 1 server prerendered
Assert.DoesNotContain("Hello Red fish", greets);
Assert.Single(greets, "Hello John");
Assert.Single(greets, "Hello Abraham");
Assert.Equal(2, greets.Where(g => g == "Hello Blue fish").Count());
Assert.Equal(3, greets.Where(g => string.Equals("Hello", g)).Count()); // 3 server prerendered without parameters
var content = Browser.FindElement(By.Id("test-container")).GetAttribute("innerHTML");
var markers = ReadMarkers(content);
@ -86,7 +87,11 @@ namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests
false,
true,
false,
true
true,
false,
true,
false,
true,
};
Assert.Equal(expectedComponentSequence, componentSequence);
@ -96,6 +101,8 @@ namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests
Browser.Exists(By.CssSelector("h3.interactive"));
var updatedGreets = Browser.FindElements(By.CssSelector(".greet-wrapper .greet")).Select(e => e.Text).ToArray();
Assert.Equal(7, updatedGreets.Where(g => string.Equals("Hello Alfred", g)).Count());
Assert.Equal(2, updatedGreets.Where(g => g == "Hello Red fish").Count());
Assert.Equal(2, updatedGreets.Where(g => g == "Hello Blue fish").Count());
Assert.Single(updatedGreets.Where(g => string.Equals("Hello Albert", g)));
Assert.Single(updatedGreets.Where(g => string.Equals("Hello Abraham", g)));
}

View File

@ -2,10 +2,12 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Text.Json;
using BasicTestApp;
using Microsoft.AspNetCore.Components.E2ETest.Infrastructure;
using Microsoft.AspNetCore.Components.E2ETest.Infrastructure.ServerFixtures;
using Microsoft.AspNetCore.E2ETesting;
using Moq;
using OpenQA.Selenium;
using OpenQA.Selenium.Support.UI;
using Xunit;
@ -1018,5 +1020,263 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
Browser.Equal(expected.DateTime, () => DateTimeOffset.Parse(boundValue.Text).DateTime);
Assert.Equal(expected.DateTime, DateTimeOffset.Parse(mirrorValue.GetAttribute("value")).DateTime);
}
// For date comparisons, we parse (non-formatted) values to compare them. Client-side and server-side
// Blazor have different formatting behaviour by default.
[Fact]
public void CanBindDateTimeLocalTextboxDateTime()
{
var target = Browser.FindElement(By.Id("datetime-local-textbox-datetime"));
var boundValue = Browser.FindElement(By.Id("datetime-local-textbox-datetime-value"));
var mirrorValue = Browser.FindElement(By.Id("datetime-local-textbox-datetime-mirror"));
var expected = new DateTime(1985, 3, 4);
Assert.Equal(expected, DateTime.Parse(target.GetAttribute("value")));
Assert.Equal(expected, DateTime.Parse(boundValue.Text));
Assert.Equal(expected, DateTime.Parse(mirrorValue.GetAttribute("value")));
// Clear textbox; value updates to 01/01/0001 because that's the default
target.Clear();
expected = default;
Browser.Equal(expected, () => DateTime.Parse(target.GetAttribute("value")));
Assert.Equal(expected, DateTime.Parse(boundValue.Text));
Assert.Equal(expected, DateTime.Parse(mirrorValue.GetAttribute("value")));
// We have to do it this way because the browser gets in the way when sending keys to the input
// element directly.
ApplyInputValue("#datetime-local-textbox-datetime", "2000-01-02T04:05:06");
expected = new DateTime(2000, 1, 2, 04, 05, 06);
Browser.Equal(expected, () => DateTime.Parse(boundValue.Text));
Assert.Equal(expected, DateTime.Parse(mirrorValue.GetAttribute("value")));
}
// For date comparisons, we parse (non-formatted) values to compare them. Client-side and server-side
// Blazor have different formatting behaviour by default.
[Fact]
public void CanBindDateTimeLocalTextboxNullableDateTime()
{
var target = Browser.FindElement(By.Id("datetime-local-textbox-nullable-datetime"));
var boundValue = Browser.FindElement(By.Id("datetime-local-textbox-nullable-datetime-value"));
var mirrorValue = Browser.FindElement(By.Id("datetime-local-textbox-nullable-datetime-mirror"));
Assert.Equal(string.Empty, target.GetAttribute("value"));
Assert.Equal(string.Empty, boundValue.Text);
Assert.Equal(string.Empty, mirrorValue.GetAttribute("value"));
// Modify target; verify value is updated and that textboxes linked to the same data are updated
target.Clear();
Browser.Equal("", () => boundValue.Text);
Assert.Equal("", mirrorValue.GetAttribute("value"));
// Modify target; verify value is updated and that textboxes linked to the same data are updated
// We have to do it this way because the browser gets in the way when sending keys to the input
// element directly.
ApplyInputValue("#datetime-local-textbox-nullable-datetime", "2000-01-02T04:05:06");
var expected = new DateTime(2000, 1, 2, 04, 05, 06);
Browser.Equal(expected, () => DateTime.Parse(boundValue.Text));
Assert.Equal(expected, DateTime.Parse(mirrorValue.GetAttribute("value")));
// Modify target; verify value is updated and that textboxes linked to the same data are updated
target.Clear();
target.SendKeys("\t");
Browser.Equal(string.Empty, () => boundValue.Text);
Assert.Equal(string.Empty, mirrorValue.GetAttribute("value"));
}
// For date comparisons, we parse (non-formatted) values to compare them. Client-side and server-side
// Blazor have different formatting behaviour by default.
[Fact]
public void CanBindMonthTextboxDateTime()
{
var target = Browser.FindElement(By.Id("month-textbox-datetime"));
var boundValue = Browser.FindElement(By.Id("month-textbox-datetime-value"));
var mirrorValue = Browser.FindElement(By.Id("month-textbox-datetime-mirror"));
var expected = new DateTime(1985, 3, 1);
Assert.Equal(expected, DateTime.Parse(target.GetAttribute("value")));
// When the value gets displayed the first time it gets truncated to the 1st day,
// until there is no change the bound value doesn't get updated.
Assert.Equal(expected.AddDays(3), DateTime.Parse(boundValue.Text));
Assert.Equal(expected.AddDays(3), DateTime.Parse(mirrorValue.GetAttribute("value")));
// Clear textbox; value updates to 01/01/0001 because that's the default
target.Clear();
expected = default;
Browser.Equal(expected, () => DateTime.Parse(target.GetAttribute("value")));
Assert.Equal(expected, DateTime.Parse(boundValue.Text));
Assert.Equal(expected, DateTime.Parse(mirrorValue.GetAttribute("value")));
// We have to do it this way because the browser gets in the way when sending keys to the input
// element directly.
ApplyInputValue("#month-textbox-datetime", "2000-02");
expected = new DateTime(2000, 2, 1);
Browser.Equal(expected, () => DateTime.Parse(boundValue.Text));
Assert.Equal(expected, DateTime.Parse(mirrorValue.GetAttribute("value")));
}
// For date comparisons, we parse (non-formatted) values to compare them. Client-side and server-side
// Blazor have different formatting behaviour by default.
[Fact]
public void CanBindMonthTextboxNullableDateTime()
{
var target = Browser.FindElement(By.Id("month-textbox-nullable-datetime"));
var boundValue = Browser.FindElement(By.Id("month-textbox-nullable-datetime-value"));
var mirrorValue = Browser.FindElement(By.Id("month-textbox-nullable-datetime-mirror"));
Assert.Equal(string.Empty, target.GetAttribute("value"));
Assert.Equal(string.Empty, boundValue.Text);
Assert.Equal(string.Empty, mirrorValue.GetAttribute("value"));
// Modify target; verify value is updated and that textboxes linked to the same data are updated
target.Clear();
Browser.Equal("", () => boundValue.Text);
Assert.Equal("", mirrorValue.GetAttribute("value"));
// Modify target; verify value is updated and that textboxes linked to the same data are updated
// We have to do it this way because the browser gets in the way when sending keys to the input
// element directly.
ApplyInputValue("#month-textbox-nullable-datetime", "2000-02");
var expected = new DateTime(2000, 2, 1);
Browser.Equal(expected, () => DateTime.Parse(boundValue.Text));
Assert.Equal(expected, DateTime.Parse(mirrorValue.GetAttribute("value")));
// Modify target; verify value is updated and that textboxes linked to the same data are updated
target.Clear();
target.SendKeys("\t");
Browser.Equal(string.Empty, () => boundValue.Text);
Assert.Equal(string.Empty, mirrorValue.GetAttribute("value"));
}
// For date comparisons, we parse (non-formatted) values to compare them. Client-side and server-side
// Blazor have different formatting behaviour by default.
[Fact]
public void CanBindTimeTextboxDateTime()
{
var target = Browser.FindElement(By.Id("time-textbox-datetime"));
var boundValue = Browser.FindElement(By.Id("time-textbox-datetime-value"));
var mirrorValue = Browser.FindElement(By.Id("time-textbox-datetime-mirror"));
var expected = DateTime.Now.Date.AddHours(8).AddMinutes(5);
Assert.Equal(expected, DateTime.Parse(target.GetAttribute("value")));
Assert.Equal(expected, DateTime.Parse(boundValue.Text));
Assert.Equal(expected, DateTime.Parse(mirrorValue.GetAttribute("value")));
// Clear textbox; value updates to 00:00 because that's the default
target.Clear();
expected = default;
Browser.Equal(DateTime.Now.Date, () => DateTime.Parse(target.GetAttribute("value")));
Assert.Equal(default, DateTime.Parse(boundValue.Text));
Assert.Equal(default, DateTime.Parse(mirrorValue.GetAttribute("value")));
// We have to do it this way because the browser gets in the way when sending keys to the input
// element directly.
ApplyInputValue("#time-textbox-datetime", "04:05");
expected = DateTime.Now.Date.Add(new TimeSpan(4, 5, 0));
Browser.Equal(expected, () => DateTime.Parse(boundValue.Text));
Assert.Equal(expected, DateTime.Parse(mirrorValue.GetAttribute("value")));
}
// For date comparisons, we parse (non-formatted) values to compare them. Client-side and server-side
// Blazor have different formatting behaviour by default.
[Fact]
public void CanBindTimeTextboxNullableDateTime()
{
var target = Browser.FindElement(By.Id("time-textbox-nullable-datetime"));
var boundValue = Browser.FindElement(By.Id("time-textbox-nullable-datetime-value"));
var mirrorValue = Browser.FindElement(By.Id("time-textbox-nullable-datetime-mirror"));
Assert.Equal(string.Empty, target.GetAttribute("value"));
Assert.Equal(string.Empty, boundValue.Text);
Assert.Equal(string.Empty, mirrorValue.GetAttribute("value"));
// Modify target; verify value is updated and that textboxes linked to the same data are updated
target.Clear();
Browser.Equal("", () => boundValue.Text);
Assert.Equal("", mirrorValue.GetAttribute("value"));
// Modify target; verify value is updated and that textboxes linked to the same data are updated
// We have to do it this way because the browser gets in the way when sending keys to the input
// element directly.
ApplyInputValue("#time-textbox-nullable-datetime", "05:06");
var expected = DateTime.Now.Date.Add(new TimeSpan(05, 06, 0));
Browser.Equal(expected, () => DateTime.Parse(boundValue.Text));
Assert.Equal(expected, DateTime.Parse(mirrorValue.GetAttribute("value")));
// Modify target; verify value is updated and that textboxes linked to the same data are updated
target.Clear();
target.SendKeys("\t");
Browser.Equal(string.Empty, () => boundValue.Text);
Assert.Equal(string.Empty, mirrorValue.GetAttribute("value"));
}
// For date comparisons, we parse (non-formatted) values to compare them. Client-side and server-side
// Blazor have different formatting behaviour by default.
[Fact]
public void CanBindTimeStepTextboxDateTime()
{
var target = Browser.FindElement(By.Id("time-step-textbox-datetime"));
var boundValue = Browser.FindElement(By.Id("time-step-textbox-datetime-value"));
var mirrorValue = Browser.FindElement(By.Id("time-step-textbox-datetime-mirror"));
var expected = DateTime.Now.Date.Add(new TimeSpan(8, 5, 30));
Assert.Equal(expected, DateTime.Parse(target.GetAttribute("value")));
Assert.Equal(expected, DateTime.Parse(boundValue.Text));
Assert.Equal(expected, DateTime.Parse(mirrorValue.GetAttribute("value")));
// Clear textbox; value updates to 00:00 because that's the default
target.Clear();
expected = default;
Browser.Equal(DateTime.Now.Date, () => DateTime.Parse(target.GetAttribute("value")));
Assert.Equal(default, DateTime.Parse(boundValue.Text));
Assert.Equal(default, DateTime.Parse(mirrorValue.GetAttribute("value")));
// We have to do it this way because the browser gets in the way when sending keys to the input
// element directly.
ApplyInputValue("#time-step-textbox-datetime", "04:05:06");
expected = DateTime.Now.Date.Add(new TimeSpan(4, 5, 6));
Browser.Equal(expected, () => DateTime.Parse(boundValue.Text));
Assert.Equal(expected, DateTime.Parse(mirrorValue.GetAttribute("value")));
}
// For date comparisons, we parse (non-formatted) values to compare them. Client-side and server-side
// Blazor have different formatting behaviour by default.
[Fact]
public void CanBindTimeStepTextboxNullableDateTime()
{
var target = Browser.FindElement(By.Id("time-step-textbox-nullable-datetime"));
var boundValue = Browser.FindElement(By.Id("time-step-textbox-nullable-datetime-value"));
var mirrorValue = Browser.FindElement(By.Id("time-step-textbox-nullable-datetime-mirror"));
Assert.Equal(string.Empty, target.GetAttribute("value"));
Assert.Equal(string.Empty, boundValue.Text);
Assert.Equal(string.Empty, mirrorValue.GetAttribute("value"));
// Modify target; verify value is updated and that textboxes linked to the same data are updated
target.Clear();
Browser.Equal("", () => boundValue.Text);
Assert.Equal("", mirrorValue.GetAttribute("value"));
// Modify target; verify value is updated and that textboxes linked to the same data are updated
// We have to do it this way because the browser gets in the way when sending keys to the input
// element directly.
ApplyInputValue("#time-step-textbox-nullable-datetime", "05:06");
var expected = DateTime.Now.Date.Add(new TimeSpan(05, 06, 0));
Browser.Equal(expected, () => DateTime.Parse(boundValue.Text));
Assert.Equal(expected, DateTime.Parse(mirrorValue.GetAttribute("value")));
// Modify target; verify value is updated and that textboxes linked to the same data are updated
target.Clear();
target.SendKeys("\t");
Browser.Equal(string.Empty, () => boundValue.Text);
Assert.Equal(string.Empty, mirrorValue.GetAttribute("value"));
}
// Applies an input through javascript to datetime-local/month/time controls.
private void ApplyInputValue(string cssSelector, string value)
{
// It's very difficult to enter an invalid value into an <input type=date>, because
// most combinations of keystrokes get normalized to something valid. Additionally,
// using Selenium's SendKeys interacts unpredictably with this normalization logic,
// most likely based on timings. As a workaround, use JS to apply the values. This
// should only be used when strictly necessary, as it doesn't represent actual user
// interaction as authentically as SendKeys in other cases.
var javascript = (IJavaScriptExecutor)Browser;
javascript.ExecuteScript(
$"var elem = document.querySelector('{cssSelector}');"
+ $"elem.value = '{value}';"
+ "elem.dispatchEvent(new KeyboardEvent('change'));");
}
}
}

View File

@ -0,0 +1,67 @@
// 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 BasicTestApp;
using Microsoft.AspNetCore.Components.E2ETest.Infrastructure;
using Microsoft.AspNetCore.Components.E2ETest.Infrastructure.ServerFixtures;
using Microsoft.AspNetCore.E2ETesting;
using OpenQA.Selenium;
using Xunit;
using Xunit.Abstractions;
namespace Microsoft.AspNetCore.Components.E2ETest.Tests
{
[Collection("ErrorNotification")] // When the clientside and serverside tests run together it seems to cause failures, possibly due to connection lose on exception.
public class ErrorNotificationClientSideTest : ServerTestBase<ToggleExecutionModeServerFixture<Program>>
{
public ErrorNotificationClientSideTest(
BrowserFixture browserFixture,
ToggleExecutionModeServerFixture<Program> serverFixture,
ITestOutputHelper output)
: base(browserFixture, serverFixture, output)
{
}
protected override void InitializeAsyncCore()
{
// On WebAssembly, page reloads are expensive so skip if possible
Navigate(ServerPathBase, noReload: _serverFixture.ExecutionMode == ExecutionMode.Client);
Browser.MountTestComponent<ErrorComponent>();
Browser.Exists(By.Id("blazor-error-ui"));
Browser.Exists(By.TagName("button"));
}
[Fact]
public void ShowsErrorNotification_OnError_Dismiss()
{
var errorUi = Browser.FindElement(By.Id("blazor-error-ui"));
Assert.Equal("none", errorUi.GetCssValue("display"));
var causeErrorButton = Browser.FindElement(By.TagName("button"));
causeErrorButton.Click();
Browser.Exists(By.CssSelector("#blazor-error-ui[style='display: block;']"), TimeSpan.FromSeconds(10));
var reload = Browser.FindElement(By.ClassName("reload"));
reload.Click();
Browser.DoesNotExist(By.TagName("button"));
}
[Fact]
public void ShowsErrorNotification_OnError_Reload()
{
var causeErrorButton = Browser.Exists(By.TagName("button"));
var errorUi = Browser.FindElement(By.Id("blazor-error-ui"));
Assert.Equal("none", errorUi.GetCssValue("display"));
causeErrorButton.Click();
Browser.Exists(By.CssSelector("#blazor-error-ui[style='display: block;']"));
var dismiss = Browser.FindElement(By.ClassName("dismiss"));
dismiss.Click();
Browser.Exists(By.CssSelector("#blazor-error-ui[style='display: none;']"));
}
}
}

View File

@ -0,0 +1,25 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using BasicTestApp;
using Microsoft.AspNetCore.Components.E2ETest.Infrastructure.ServerFixtures;
using Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests;
using Microsoft.AspNetCore.E2ETesting;
using OpenQA.Selenium;
using Xunit;
using Xunit.Abstractions;
namespace Microsoft.AspNetCore.Components.E2ETest.Tests
{
[Collection("ErrorNotification")] // When the clientside and serverside tests run together it seems to cause failures, possibly due to connection lose on exception.
public class ErrorNotificationServerSideTest : ErrorNotificationClientSideTest
{
public ErrorNotificationServerSideTest(
BrowserFixture browserFixture,
ToggleExecutionModeServerFixture<Program> serverFixture,
ITestOutputHelper output)
: base(browserFixture, serverFixture.WithServerExecution(), output)
{
}
}
}

View File

@ -376,6 +376,24 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
Browser.Equal("Premium", () => selectedTicketClassDisplay.Text);
}
[Fact]
public void InputComponentsRespondToAsynchronouslyAddedMessages()
{
var appElement = Browser.MountTestComponent<TypicalValidationComponent>();
var input = appElement.FindElement(By.CssSelector(".username input"));
var triggerAsyncErrorButton = appElement.FindElement(By.CssSelector(".username button"));
var messagesAccessor = CreateValidationMessagesAccessor(appElement);
// Initially shows no error
Browser.Empty(() => messagesAccessor());
Browser.Equal("valid", () => input.GetAttribute("class"));
// Can trigger async error
triggerAsyncErrorButton.Click();
Browser.Equal(new[] { "This is invalid, asynchronously" }, messagesAccessor);
Browser.Equal("invalid", () => input.GetAttribute("class"));
}
private Func<string[]> CreateValidationMessagesAccessor(IWebElement appElement)
{
return () => appElement.FindElements(By.ClassName("validation-message"))

View File

@ -11,6 +11,7 @@ using OpenQA.Selenium;
using OpenQA.Selenium.Support.UI;
using Xunit;
using Xunit.Abstractions;
using Xunit.Sdk;
namespace Microsoft.AspNetCore.Components.E2ETest.Tests
{
@ -68,6 +69,8 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
["testDtoAsync"] = "Same",
["returnPrimitiveAsync"] = "123",
["returnArrayAsync"] = "first,second",
["syncGenericInstanceMethod"] = @"""Initial value""",
["asyncGenericInstanceMethod"] = @"""Updated value 1""",
};
var expectedSyncValues = new Dictionary<string, string>
@ -102,6 +105,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
["testDtoSync"] = "Same",
["returnPrimitive"] = "123",
["returnArray"] = "first,second",
["genericInstanceMethod"] = @"""Updated value 2""",
};
// Include the sync assertions only when running under WebAssembly
@ -132,13 +136,17 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
// Assert
foreach (var expectedValue in expectedValues)
{
var actualValue = actualValues[expectedValue.Key];
if (expectedValue.Key.Contains("Exception"))
{
Assert.StartsWith(expectedValue.Value, actualValues[expectedValue.Key]);
Assert.StartsWith(expectedValue.Value, actualValue);
}
else
{
Assert.Equal(expectedValue.Value, actualValues[expectedValue.Key]);
if (expectedValue.Value != actualValue)
{
throw new AssertActualExpectedException(expectedValue.Value, actualValue, $"Scenario '{expectedValue.Key}' failed. Expected '{expectedValue.Value}, Actual {actualValue}");
}
}
}
}

View File

@ -254,6 +254,63 @@
<span id="select-markup-box-value">@selectMarkupValue</span>
</p>
<h2>Time related inputs (datetime-local, month, time)</h2>
<h3>datetime-local</h3>
<p>
DateTime:
<input id="datetime-local-textbox-datetime" @bind="dateTimeLocalTextboxDateTimeValue" type="datetime-local" />
<span id="datetime-local-textbox-datetime-value">@dateTimeLocalTextboxDateTimeValue</span>
<input id="datetime-local-textbox-datetime-mirror" @bind="dateTimeLocalTextboxDateTimeValue" readonly />
</p>
<p>
Nullable DateTime:
<input id="datetime-local-textbox-nullable-datetime" @bind-value="dateTimeLocalTextboxNullableDateTimeValue" type="datetime-local" />
<span id="datetime-local-textbox-nullable-datetime-value">@dateTimeLocalTextboxNullableDateTimeValue</span>
<input id="datetime-local-textbox-nullable-datetime-mirror" @bind="dateTimeLocalTextboxNullableDateTimeValue" readonly />
</p>
<h3>month</h3>
<p>
DateTime:
<input id="month-textbox-datetime" @bind="monthTextboxDateTimeValue" type="month" />
<span id="month-textbox-datetime-value">@monthTextboxDateTimeValue</span>
<input id="month-textbox-datetime-mirror" @bind="monthTextboxDateTimeValue" readonly />
</p>
<p>
Nullable DateTime:
<input id="month-textbox-nullable-datetime" @bind-value="monthTextboxNullableDateTimeValue" type="month" />
<span id="month-textbox-nullable-datetime-value">@monthTextboxNullableDateTimeValue</span>
<input id="month-textbox-nullable-datetime-mirror" @bind="monthTextboxNullableDateTimeValue" readonly />
</p>
<h3>time</h3>
<p>
DateTime:
<input id="time-textbox-datetime" @bind="timeTextboxDateTimeValue" type="time" />
<span id="time-textbox-datetime-value">@timeTextboxDateTimeValue</span>
<input id="time-textbox-datetime-mirror" @bind="timeTextboxDateTimeValue" readonly />
</p>
<p>
Nullable DateTime:
<input id="time-textbox-nullable-datetime" @bind-value="timeTextboxNullableDateTimeValue" type="time" />
<span id="time-textbox-nullable-datetime-value">@timeTextboxNullableDateTimeValue</span>
<input id="time-textbox-nullable-datetime-mirror" @bind="timeTextboxNullableDateTimeValue" readonly />
</p>
<h3>time with step (supports seconds)</h3>
<p>
DateTime:
<input id="time-step-textbox-datetime" @bind="timeStepTextboxDateTimeValue" type="time" step="1" />
<span id="time-step-textbox-datetime-value">@timeStepTextboxDateTimeValue</span>
<input id="time-step-textbox-datetime-mirror" @bind="timeStepTextboxDateTimeValue" readonly />
</p>
<p>
Nullable DateTime:
<input id="time-step-textbox-nullable-datetime" @bind-value="timeStepTextboxNullableDateTimeValue" type="time" step="1" />
<span id="time-step-textbox-nullable-datetime-value">@timeStepTextboxNullableDateTimeValue</span>
<input id="time-step-textbox-nullable-datetime-mirror" @bind="timeStepTextboxNullableDateTimeValue" readonly />
</p>
@code {
string textboxInitiallyBlankValue = null;
string textboxInitiallyPopulatedValue = "Hello";
@ -297,6 +354,18 @@
DateTime textboxDateTimeFormatInvalidValue = new DateTime(1985, 3, 4);
DateTimeOffset? textboxNullableDateTimeOffsetFormatInvalidValue = null;
DateTime dateTimeLocalTextboxDateTimeValue = new DateTime(1985, 3, 4);
DateTime? dateTimeLocalTextboxNullableDateTimeValue = null;
DateTime monthTextboxDateTimeValue = new DateTime(1985, 3, 4);
DateTime? monthTextboxNullableDateTimeValue = null;
DateTime timeTextboxDateTimeValue = DateTime.Now.Date.Add(new TimeSpan(8, 5, 0));
DateTime? timeTextboxNullableDateTimeValue = null;
DateTime timeStepTextboxDateTimeValue = DateTime.Now.Date.Add(new TimeSpan(8, 5, 30));
DateTime? timeStepTextboxNullableDateTimeValue = null;
bool includeFourthOption = false;
enum SelectableValue { First, Second, Third, Fourth }
SelectableValue selectValue = SelectableValue.Second;

View File

@ -0,0 +1,48 @@
<h3 class="interactive">Component With Parameters</h3>
<ul class="Param1">
@foreach (var value in Param1)
{
<li>@value.StringProperty @value.IntProperty</li>
}
</ul>
@* Making sure polymorphism works *@
<div class="Param2">@DerivedParam2.StringProperty @DerivedParam2.DerivedProperty</div>
@* Making sure CaptureUnmatchedValues works *@
<ul class="Param3">
@foreach (var value in Param3.OrderBy(kvp => kvp.Key))
{
<li>@value.Key @value.Value</li>
}
</ul>
@code
{
[Parameter] public List<TestModel> Param1 { get; set; }
[Parameter] public TestModel Param2 { get; set; }
[Parameter(CaptureUnmatchedValues = true)] public IDictionary<string, object> Param3 { get; set; }
private DerivedModel DerivedParam2 => (DerivedModel)Param2;
public static List<TestModel> TestModelValues => Enumerable.Range(0, 100).Select(c => new TestModel { StringProperty = c.ToString(), IntProperty = c }).ToList();
public static DerivedModel DerivedModelValue = new DerivedModel { StringProperty = "Value", DerivedProperty = "Derived-Value" };
public class TestModel
{
public string StringProperty { get; set; }
public int IntProperty { get; set; }
}
public class DerivedModel : TestModel
{
public string DerivedProperty { get; set; }
}
}

View File

@ -0,0 +1,16 @@
<div>
<h2>Error throwing button</h2>
<p>
<button @onclick="@(IncrementCount)">Click me</button>
</p>
</div>
@code {
int currentCount = 0;
void IncrementCount()
{
currentCount++;
throw new NotImplementedException("Doing crazy things!");
}
}

View File

@ -1,7 +1,7 @@
@using System.ComponentModel.DataAnnotations
@using Microsoft.AspNetCore.Components.Forms
<EditForm Model="@person" OnValidSubmit="@HandleValidSubmit">
<EditForm EditContext="@editContext" OnValidSubmit="@HandleValidSubmit">
<DataAnnotationsValidator />
<p class="name">
@ -42,6 +42,10 @@
<p class="is-evil">
Is evil: <InputCheckbox @bind-Value="person.IsEvil" />
</p>
<p class="username">
Username (optional): <InputText @bind-Value="person.Username" />
<button type="button" @onclick="@TriggerAsyncValidationError">Trigger async error</button>
</p>
<button type="submit">Submit</button>
@ -52,6 +56,14 @@
@code {
Person person = new Person();
EditContext editContext;
ValidationMessageStore customValidationMessageStore;
protected override void OnInitialized()
{
editContext = new EditContext(person);
customValidationMessageStore = new ValidationMessageStore(editContext);
}
// Usually this would be in a different file
class Person
@ -83,6 +95,8 @@
[Required, EnumDataType(typeof(TicketClass))]
public TicketClass TicketClass { get; set; }
public string Username { get; set; }
}
enum TicketClass { Economy, Premium, First }
@ -93,4 +107,22 @@
{
submissionLog.Add("OnValidSubmit");
}
void TriggerAsyncValidationError()
{
customValidationMessageStore.Clear();
// Note that this method returns void, so the renderer doesn't react to
// its async flow by default. This is to simulate some external system
// implementing async validation.
Task.Run(async () =>
{
// The duration of the delay doesn't matter to the test, as long as it's not
// so long that we time out. Picking a value that's long enough for humans
// to observe the asynchrony too.
await Task.Delay(500);
customValidationMessageStore.Add(editContext.Field(nameof(Person.Username)), "This is invalid, asynchronously");
_ = InvokeAsync(editContext.NotifyValidationStateChanged);
});
}
}

View File

@ -62,6 +62,10 @@
int: <InputNumber id="inputnumber_int" @bind-Value="inputNumberInt" />
<span id="inputnumber_int_value">@inputNumberInt</span>
</div>
<div>
long: <InputNumber id="inputnumber_long" @bind-Value="inputNumberLong" />
<span id="inputnumber_long_value">@inputNumberLong</span>
</div>
<div>
decimal: <InputNumber id="inputnumber_decimal" @bind-Value="inputNumberDecimal" />
<span id="inputnumber_decimal_value">@inputNumberDecimal</span>
@ -99,8 +103,18 @@
DateTimeOffset inputTypeDateDateTimeOffset = new DateTimeOffset(new DateTime(1985, 3, 4));
int inputNumberInt = 42;
long inputNumberLong = 4200;
decimal inputNumberDecimal = 4.2m;
DateTime inputDateDateTime = new DateTime(1985, 3, 4);
DateTimeOffset inputDateDateTimeOffset = new DateTimeOffset(new DateTime(1985, 3, 4));
DateTime inputTypeDateTimeLocalDateTime = new DateTime(1985, 3, 4);
DateTimeOffset inputTypeDateTimeLocalDateTimeOffset = new DateTimeOffset(new DateTime(1985, 3, 4));
DateTime inputTypeMonthDateTime = new DateTime(1985, 3, 4);
DateTimeOffset inputTypeMonthDateTimeOffset = new DateTimeOffset(new DateTime(1985, 3, 4));
DateTime inputTypeTimeDateTime = new DateTime(1985, 3, 4);
DateTimeOffset inputTypeTimeDateTimeOffset = new DateTimeOffset(new DateTime(1985, 3, 4));
}

View File

@ -1,6 +1,6 @@
@using Microsoft.AspNetCore.Components.Rendering
<div id="test-selector">
Select test:
Select test:
<select id="test-selector-select" @bind=SelectedComponentTypeName>
<option value="none">Choose...</option>
<option value="BasicTestApp.AddRemoveChildComponents">Add/remove child components</option>
@ -20,6 +20,7 @@
<option value="BasicTestApp.DispatchingComponent">Dispatching to sync context</option>
<option value="BasicTestApp.DuplicateAttributesComponent">Duplicate attributes</option>
<option value="BasicTestApp.ElementRefComponent">Element ref component</option>
<option value="BasicTestApp.ErrorComponent">Error throwing</option>
<option value="BasicTestApp.EventBubblingComponent">Event bubbling</option>
<option value="BasicTestApp.EventCallbackTest.EventCallbackCases">EventCallback</option>
<option value="BasicTestApp.EventCasesComponent">Event cases</option>
@ -82,6 +83,12 @@
@((RenderFragment)RenderSelectedComponent)
</app>
<div id="blazor-error-ui">
An unhandled error has occurred.
<a href class='reload'>Reload</a>
<a class='dismiss' style="cursor: pointer;">🗙</a>
</div>
@code {
string SelectedComponentTypeName { get; set; } = "none";

View File

@ -70,13 +70,15 @@
var shouldSupportSyncInterop = RuntimeInformation.IsOSPlatform(OSPlatform.Create("WEBASSEMBLY"));
var testDTOTOPassByRef = new TestDTO(nonSerializedValue: 123);
var instanceMethodsTarget = new JavaScriptInterop();
var genericType = new JavaScriptInterop.GenericType<string> { Value = "Initial value" };
Console.WriteLine("Starting interop invocations.");
await JSRuntime.InvokeVoidAsync(
"jsInteropTests.invokeDotNetInteropMethodsAsync",
shouldSupportSyncInterop,
DotNetObjectReference.Create(testDTOTOPassByRef),
DotNetObjectReference.Create(instanceMethodsTarget));
DotNetObjectReference.Create(instanceMethodsTarget),
DotNetObjectReference.Create(genericType));
if (shouldSupportSyncInterop)
{

View File

@ -462,5 +462,25 @@ namespace BasicTestApp.InteropTest
public DotNetObjectReference<TestDTO> OutgoingByRef { get; set; }
}
public class GenericType<TValue>
{
public TValue Value { get; set; }
[JSInvokable]
public TValue Update(TValue newValue)
{
var oldValue = Value;
Value = newValue;
return oldValue;
}
[JSInvokable]
public async Task<TValue> UpdateAsync(TValue newValue)
{
await Task.Yield();
return Update(newValue);
}
}
}
}

View File

@ -14,7 +14,7 @@
<li><NavLink href="/subdir/Default.html">With extension</NavLink></li>
<li><NavLink href="/subdir/Other">Other</NavLink></li>
<li><NavLink href="Other" Match=NavLinkMatch.All>Other with base-relative URL (matches all)</NavLink></li>
<li><NavLink href="/subdir/Other?abc=123">Other with query</NavLink></li>
<li><NavLink href="/subdir/other?abc=123">Other with query</NavLink></li>
<li><NavLink href="/subdir/Other#blah">Other with hash</NavLink></li>
<li><NavLink href="/subdir/WithParameters/Name/Abc">With parameters</NavLink></li>
<li><NavLink href="/subdir/WithParameters/Name/Abc/LastName/McDef">With more parameters</NavLink></li>

View File

@ -1,5 +1,6 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Basic test app</title>
@ -9,6 +10,7 @@
<!-- Used by ExternalContentPackage -->
<link href="_content/TestContentPackage/styles.css" rel="stylesheet" />
</head>
<body>
<root>Loading...</root>
@ -31,4 +33,5 @@
<!-- Used by ExternalContentPackage -->
<script src="_content/TestContentPackage/prompt.js"></script>
</body>
</html>

View File

@ -2,7 +2,7 @@
var results = {};
var assemblyName = 'BasicTestApp';
function invokeDotNetInteropMethodsAsync(shouldSupportSyncInterop, dotNetObjectByRef, instanceMethodsTarget) {
async function invokeDotNetInteropMethodsAsync(shouldSupportSyncInterop, dotNetObjectByRef, instanceMethodsTarget, genericDotNetObjectByRef) {
if (shouldSupportSyncInterop) {
console.log('Invoking void sync methods.');
DotNet.invokeMethod(assemblyName, 'VoidParameterless');
@ -15,6 +15,7 @@ function invokeDotNetInteropMethodsAsync(shouldSupportSyncInterop, dotNetObjectB
DotNet.invokeMethod(assemblyName, 'VoidWithSevenParameters', ...createArgumentList(7, dotNetObjectByRef));
DotNet.invokeMethod(assemblyName, 'VoidWithEightParameters', ...createArgumentList(8, dotNetObjectByRef));
console.log('Invoking returning sync methods.');
results['result1'] = DotNet.invokeMethod(assemblyName, 'ReturnArray');
results['result2'] = DotNet.invokeMethod(assemblyName, 'EchoOneParameter', ...createArgumentList(1, dotNetObjectByRef));
@ -40,75 +41,73 @@ function invokeDotNetInteropMethodsAsync(shouldSupportSyncInterop, dotNetObjectB
}
console.log('Invoking void async methods.');
return DotNet.invokeMethodAsync(assemblyName, 'VoidParameterlessAsync')
.then(() => DotNet.invokeMethodAsync(assemblyName, 'VoidWithOneParameterAsync', ...createArgumentList(1, dotNetObjectByRef)))
.then(() => DotNet.invokeMethodAsync(assemblyName, 'VoidWithTwoParametersAsync', ...createArgumentList(2, dotNetObjectByRef)))
.then(() => DotNet.invokeMethodAsync(assemblyName, 'VoidWithThreeParametersAsync', ...createArgumentList(3, dotNetObjectByRef)))
.then(() => DotNet.invokeMethodAsync(assemblyName, 'VoidWithFourParametersAsync', ...createArgumentList(4, dotNetObjectByRef)))
.then(() => DotNet.invokeMethodAsync(assemblyName, 'VoidWithFiveParametersAsync', ...createArgumentList(5, dotNetObjectByRef)))
.then(() => DotNet.invokeMethodAsync(assemblyName, 'VoidWithSixParametersAsync', ...createArgumentList(6, dotNetObjectByRef)))
.then(() => DotNet.invokeMethodAsync(assemblyName, 'VoidWithSevenParametersAsync', ...createArgumentList(7, dotNetObjectByRef)))
.then(() => DotNet.invokeMethodAsync(assemblyName, 'VoidWithEightParametersAsync', ...createArgumentList(8, dotNetObjectByRef)))
.then(() => {
console.log('Invoking returning async methods.');
return DotNet.invokeMethodAsync(assemblyName, 'ReturnArrayAsync')
.then(r => results['result1Async'] = r)
.then(() => DotNet.invokeMethodAsync(assemblyName, 'EchoOneParameterAsync', ...createArgumentList(1, dotNetObjectByRef)))
.then(r => results['result2Async'] = r)
.then(() => DotNet.invokeMethodAsync(assemblyName, 'EchoTwoParametersAsync', ...createArgumentList(2, dotNetObjectByRef)))
.then(r => results['result3Async'] = r)
.then(() => DotNet.invokeMethodAsync(assemblyName, 'EchoThreeParametersAsync', ...createArgumentList(3, dotNetObjectByRef)))
.then(r => results['result4Async'] = r)
.then(() => DotNet.invokeMethodAsync(assemblyName, 'EchoFourParametersAsync', ...createArgumentList(4, dotNetObjectByRef)))
.then(r => results['result5Async'] = r)
.then(() => DotNet.invokeMethodAsync(assemblyName, 'EchoFiveParametersAsync', ...createArgumentList(5, dotNetObjectByRef)))
.then(r => results['result6Async'] = r)
.then(() => DotNet.invokeMethodAsync(assemblyName, 'EchoSixParametersAsync', ...createArgumentList(6, dotNetObjectByRef)))
.then(r => results['result7Async'] = r)
.then(() => DotNet.invokeMethodAsync(assemblyName, 'EchoSevenParametersAsync', ...createArgumentList(7, dotNetObjectByRef)))
.then(r => results['result8Async'] = r)
.then(() => DotNet.invokeMethodAsync(assemblyName, 'EchoEightParametersAsync', ...createArgumentList(8, dotNetObjectByRef)))
.then(r => results['result9Async'] = r)
.then(() => DotNet.invokeMethodAsync(assemblyName, 'ReturnDotNetObjectByRefAsync'))
.then(r => DotNet.invokeMethodAsync(assemblyName, 'ExtractNonSerializedValue', r['Some async instance']))
.then(r => {
results['resultReturnDotNetObjectByRefAsync'] = r;
})
.then(() => instanceMethodsTarget.invokeMethodAsync('InstanceMethodAsync', {
stringValue: 'My string',
dtoByRef: dotNetObjectByRef
}))
.then(r => {
results['instanceMethodThisTypeNameAsync'] = r.thisTypeName;
results['instanceMethodStringValueUpperAsync'] = r.stringValueUpper;
results['instanceMethodIncomingByRefAsync'] = r.incomingByRef;
return DotNet.invokeMethodAsync(assemblyName, 'ExtractNonSerializedValue', r.outgoingByRef);
}).then(r => {
results['instanceMethodOutgoingByRefAsync'] = r;
})
})
.then(() => {
console.log('Invoking methods that throw exceptions');
try {
shouldSupportSyncInterop && DotNet.invokeMethod(assemblyName, 'ThrowException');
} catch (e) {
results['ThrowException'] = e.message;
}
return DotNet.invokeMethodAsync(assemblyName, 'AsyncThrowSyncException')
.catch(e => {
results['AsyncThrowSyncException'] = e.message;
await DotNet.invokeMethodAsync(assemblyName, 'VoidParameterlessAsync');
await DotNet.invokeMethodAsync(assemblyName, 'VoidWithOneParameterAsync', ...createArgumentList(1, dotNetObjectByRef));
await DotNet.invokeMethodAsync(assemblyName, 'VoidWithTwoParametersAsync', ...createArgumentList(2, dotNetObjectByRef));
await DotNet.invokeMethodAsync(assemblyName, 'VoidWithThreeParametersAsync', ...createArgumentList(3, dotNetObjectByRef));
await DotNet.invokeMethodAsync(assemblyName, 'VoidWithFourParametersAsync', ...createArgumentList(4, dotNetObjectByRef));
await DotNet.invokeMethodAsync(assemblyName, 'VoidWithFiveParametersAsync', ...createArgumentList(5, dotNetObjectByRef));
await DotNet.invokeMethodAsync(assemblyName, 'VoidWithSixParametersAsync', ...createArgumentList(6, dotNetObjectByRef));
await DotNet.invokeMethodAsync(assemblyName, 'VoidWithSevenParametersAsync', ...createArgumentList(7, dotNetObjectByRef));
await DotNet.invokeMethodAsync(assemblyName, 'VoidWithEightParametersAsync', ...createArgumentList(8, dotNetObjectByRef));
return DotNet.invokeMethodAsync(assemblyName, 'AsyncThrowAsyncException');
}).catch(e => {
results['AsyncThrowAsyncException'] = e.message;
console.log('Invoking returning async methods.');
results['result1Async'] = await DotNet.invokeMethodAsync(assemblyName, 'ReturnArrayAsync');
results['result2Async'] = await DotNet.invokeMethodAsync(assemblyName, 'EchoOneParameterAsync', ...createArgumentList(1, dotNetObjectByRef));
results['result3Async'] = await DotNet.invokeMethodAsync(assemblyName, 'EchoTwoParametersAsync', ...createArgumentList(2, dotNetObjectByRef));
results['result4Async'] = await DotNet.invokeMethodAsync(assemblyName, 'EchoThreeParametersAsync', ...createArgumentList(3, dotNetObjectByRef));
results['result5Async'] = await DotNet.invokeMethodAsync(assemblyName, 'EchoFourParametersAsync', ...createArgumentList(4, dotNetObjectByRef));
results['result6Async'] = await DotNet.invokeMethodAsync(assemblyName, 'EchoFiveParametersAsync', ...createArgumentList(5, dotNetObjectByRef));
results['result7Async'] = await DotNet.invokeMethodAsync(assemblyName, 'EchoSixParametersAsync', ...createArgumentList(6, dotNetObjectByRef));
results['result8Async'] = await DotNet.invokeMethodAsync(assemblyName, 'EchoSevenParametersAsync', ...createArgumentList(7, dotNetObjectByRef));
results['result9Async'] = await DotNet.invokeMethodAsync(assemblyName, 'EchoEightParametersAsync', ...createArgumentList(8, dotNetObjectByRef));
console.log('Done invoking interop methods');
});
});
const returnDotNetObjectByRefAsync = await DotNet.invokeMethodAsync(assemblyName, 'ReturnDotNetObjectByRefAsync');
results['resultReturnDotNetObjectByRefAsync'] = await DotNet.invokeMethodAsync(assemblyName, 'ExtractNonSerializedValue', returnDotNetObjectByRefAsync['Some async instance']);
const instanceMethodAsync = await instanceMethodsTarget.invokeMethodAsync('InstanceMethodAsync', {
stringValue: 'My string',
dtoByRef: dotNetObjectByRef
});
results['instanceMethodThisTypeNameAsync'] = instanceMethodAsync.thisTypeName;
results['instanceMethodStringValueUpperAsync'] = instanceMethodAsync.stringValueUpper;
results['instanceMethodIncomingByRefAsync'] = instanceMethodAsync.incomingByRef;
results['instanceMethodOutgoingByRefAsync'] = await DotNet.invokeMethodAsync(assemblyName, 'ExtractNonSerializedValue', instanceMethodAsync.outgoingByRef);
console.log('Invoking generic type instance methods.');
results['syncGenericInstanceMethod'] = await genericDotNetObjectByRef.invokeMethodAsync('Update', 'Updated value 1');
results['asyncGenericInstanceMethod'] = await genericDotNetObjectByRef.invokeMethodAsync('UpdateAsync', 'Updated value 2');
if (shouldSupportSyncInterop) {
results['genericInstanceMethod'] = genericDotNetObjectByRef.invokeMethod('Update', 'Updated Value 3');
}
console.log('Invoking methods that throw exceptions');
try {
shouldSupportSyncInterop && DotNet.invokeMethod(assemblyName, 'ThrowException');
} catch (e) {
results['ThrowException'] = e.message;
}
try {
await DotNet.invokeMethodAsync(assemblyName, 'AsyncThrowSyncException');
} catch (e) {
results['AsyncThrowSyncException'] = e.message;
}
try {
await DotNet.invokeMethodAsync(assemblyName, 'AsyncThrowAsyncException');
} catch (e) {
results['AsyncThrowAsyncException'] = e.message;
}
console.log('Done invoking interop methods');
}
function createArgumentList(argumentNumber, dotNetObjectByRef){
function createArgumentList(argumentNumber, dotNetObjectByRef) {
const array = new Array(argumentNumber);
if (argumentNumber === 0) {
return [];
@ -149,7 +148,7 @@ function createArgumentList(argumentNumber, dotNetObjectByRef){
source: `Some random text with at least ${i} characters`,
start: argumentNumber + 1,
length: argumentNumber + 1
}
};
break;
default:
console.log(i);
@ -169,7 +168,7 @@ window.jsInteropTests = {
returnPrimitive: returnPrimitive,
returnPrimitiveAsync: returnPrimitiveAsync,
receiveDotNetObjectByRef: receiveDotNetObjectByRef,
receiveDotNetObjectByRefAsync: receiveDotNetObjectByRefAsync,
receiveDotNetObjectByRefAsync: receiveDotNetObjectByRefAsync
};
function returnPrimitive() {
@ -211,9 +210,9 @@ function asyncFunctionThrowsAsyncException() {
}
function asyncFunctionTakesLongerThanDefaultTimeoutToResolve() {
return new Promise((resolve, reject) => {
setTimeout(() => resolve(undefined), 5000);
});
return new Promise((resolve, reject) => {
setTimeout(() => resolve(undefined), 5000);
});
}
function collectInteropResults() {

View File

@ -6,6 +6,14 @@
outline: 1px solid red;
}
#blazor-error-ui {
display: none;
}
#blazor-error-ui dismiss {
cursor: pointer;
}
.validation-message {
color: red;
}

View File

@ -12,7 +12,7 @@
<link href="css/site.css" rel="stylesheet" />
</head>
<body>
<app>@(await Html.RenderComponentAsync<App>(RenderMode.Server))</app>
<component type="typeof(App)" render-mode="Server" />
<script src="_framework/blazor.server.js" autostart="false"></script>
<script>
Blazor.start({

View File

@ -0,0 +1,51 @@
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace TestServer
{
public class MultipleComponents
{
public MultipleComponents(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddServerSideBlazor();
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.Map("/multiple-components", app =>
{
app.UseStaticFiles();
app.UseAuthentication();
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
endpoints.MapFallbackToPage("/MultipleComponents");
endpoints.MapBlazorHub();
});
});
}
}
}

View File

@ -0,0 +1,37 @@
@page
<component type="typeof(ComponentWithParameters)"
render-mode="ServerPrerendered"
param-Param1="ComponentWithParameters.TestModelValues"
param-Param2="ComponentWithParameters.DerivedModelValue"
param-key1="QueryValue"
param-key2="43" />
@*
So that E2E tests can make assertions about both the prerendered and
interactive states, we only load the .js file when told to.
*@
<hr />
<button id="load-boot-script" onclick="start()">Load boot script</button>
<script src="_framework/blazor.server.js" autostart="false"></script>
<script>
// Used by InteropOnInitializationComponent
function setElementValue(element, newValue) {
element.value = newValue;
return element.value;
}
function start() {
Blazor.start({
logLevel: 1 // LogLevel.Debug
});
}
</script>
@functions
{
[BindProperty(SupportsGet = true)]
public string QueryValue { get; set; }
}

View File

@ -1,59 +1,29 @@
@page "/multiple-components"
@using BasicTestApp.MultipleComponents;
<!DOCTYPE html>
<html>
<head>
<title>Multiple component entry points</title>
<base href="~/" />
@* This page is used to validate the ability to render multiple root components in a blazor server-side application.
*@
</head>
<body>
<div id="test-container">
@(await Html.RenderComponentAsync<GreeterComponent>(RenderMode.ServerPrerendered))
@(await Html.RenderComponentAsync<GreeterComponent>(RenderMode.Server))
@(await Html.RenderComponentAsync<GreeterComponent>(RenderMode.Static, new { Name = "John" }))
@(await Html.RenderComponentAsync<GreeterComponent>(RenderMode.Server))
<div id="container">
<p>Some content before</p>
@(await Html.RenderComponentAsync<GreeterComponent>(RenderMode.Server))
<p>Some content between</p>
@(await Html.RenderComponentAsync<GreeterComponent>(RenderMode.ServerPrerendered))
<p>Some content after</p>
<div id="nested-an-extra-level">
<p>Some content before</p>
@(await Html.RenderComponentAsync<GreeterComponent>(RenderMode.Server))
@(await Html.RenderComponentAsync<GreeterComponent>(RenderMode.ServerPrerendered))
<p>Some content after</p>
</div>
</div>
<div id="container">
@(await Html.RenderComponentAsync<GreeterComponent>(RenderMode.Server, new { Name = "Albert" }))
@(await Html.RenderComponentAsync<GreeterComponent>(RenderMode.ServerPrerendered, new { Name = "Abraham" }))
</div>
@{
Layout = "./MultipleComponentsLayout.cshtml";
}
@(await Html.RenderComponentAsync<GreeterComponent>(RenderMode.ServerPrerendered))
@(await Html.RenderComponentAsync<GreeterComponent>(RenderMode.Server))
<component type="typeof(GreeterComponent)" render-mode="Static" param-name='"John"' />
<component type="typeof(GreeterComponent)" render-mode="Server" />
<div id="container">
<p>Some content before</p>
<component type="typeof(GreeterComponent)" render-mode="Server" />
<p>Some content between</p>
<component type="typeof(GreeterComponent)" render-mode="ServerPrerendered" />
<p>Some content after</p>
<div id="nested-an-extra-level">
<p>Some content before</p>
<component type="typeof(GreeterComponent)" render-mode="Server" />
<component type="typeof(GreeterComponent)" render-mode="ServerPrerendered" />
<p>Some content after</p>
</div>
@*
So that E2E tests can make assertions about both the prerendered and
interactive states, we only load the .js file when told to.
*@
<hr />
<button id="load-boot-script" onclick="start()">Load boot script</button>
<script src="_framework/blazor.server.js" autostart="false"></script>
<script>
// Used by InteropOnInitializationComponent
function setElementValue(element, newValue) {
element.value = newValue;
return element.value;
}
function start() {
Blazor.start({
logLevel: 1 // LogLevel.Debug
});
}
</script>
</body>
</html>
</div>
<div id="container">
<component type="typeof(GreeterComponent)" render-mode="Server" param-name='"Albert"' />
<component type="typeof(GreeterComponent)" render-mode="ServerPrerendered" param-name='"Abraham"' />
</div>

View File

@ -0,0 +1,43 @@
@using BasicTestApp.MultipleComponents;
<!DOCTYPE html>
<html>
<head>
<title>Multiple component entry points</title>
<base href="~/" />
@* This page is used to validate the ability to render multiple root components in a blazor server-side application.
*@
</head>
<body>
<div id="test-container">
<component type="typeof(GreeterComponent)" render-mode="Server" param-name='"Red fish"' />
<component type="typeof(GreeterComponent)" render-mode="ServerPrerendered" param-name='"Blue fish"' />
@RenderBody()
<component type="typeof(GreeterComponent)" render-mode="Server" param-name='"Red fish"' />
<component type="typeof(GreeterComponent)" render-mode="ServerPrerendered" param-name='"Blue fish"' />
</div>
@*
So that E2E tests can make assertions about both the prerendered and
interactive states, we only load the .js file when told to.
*@
<hr />
<button id="load-boot-script" onclick="start()">Load boot script</button>
<script src="_framework/blazor.server.js" autostart="false"></script>
<script>
// Used by InteropOnInitializationComponent
function setElementValue(element, newValue) {
element.value = newValue;
return element.value;
}
function start() {
Blazor.start({
logLevel: 1 // LogLevel.Debug
});
}
</script>
</body>
</html>

View File

@ -1,5 +1,6 @@
@page
@using BasicTestApp.RouterTest
<!DOCTYPE html>
<html>
<head>
@ -7,7 +8,7 @@
<base href="~/" />
</head>
<body>
<app>@(await Html.RenderComponentAsync<TestRouter>(RenderMode.ServerPrerendered))</app>
<app><component type="typeof(TestRouter)" render-mode="ServerPrerendered" /></app>
@*
So that E2E tests can make assertions about both the prerendered and

View File

@ -1,4 +1,5 @@
@page ""
@addTagHelper "*, Microsoft.AspNetCore.Mvc.TagHelpers"
<!DOCTYPE html>
<html>
<head>
@ -11,7 +12,7 @@
<link href="_content/TestContentPackage/styles.css" rel="stylesheet" />
</head>
<body>
<root>@(await Html.RenderComponentAsync<BasicTestApp.Index>(RenderMode.Server))</root>
<root><component type="typeof(BasicTestApp.Index)" render-mode="Server" /></root>
<!-- Used for testing interop scenarios between JS and .NET -->
<script src="js/jsinteroptests.js"></script>

View File

@ -0,0 +1,3 @@
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@using BasicTestApp

View File

@ -1,15 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.Hosting.Server.Features;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
@ -28,6 +23,7 @@ namespace TestServer
["Server authentication"] = (BuildWebHost<ServerAuthenticationStartup>(CreateAdditionalArgs(args)), "/subdir"),
["CORS (WASM)"] = (BuildWebHost<CorsStartup>(CreateAdditionalArgs(args)), "/subdir"),
["Prerendering (Server-side)"] = (BuildWebHost<PrerenderedStartup>(CreateAdditionalArgs(args)), "/prerendered"),
["Multiple components (Server-side)"] = (BuildWebHost<MultipleComponents>(CreateAdditionalArgs(args)), "/multiple-components"),
["Globalization + Localization (Server-side)"] = (BuildWebHost<InternationalizationStartup>(CreateAdditionalArgs(args)), "/subdir"),
["Server-side blazor"] = (BuildWebHost<ServerStartup>(CreateAdditionalArgs(args)), "/subdir"),
["Hosted client-side blazor"] = (BuildWebHost<ClientStartup>(CreateAdditionalArgs(args)), "/subdir"),

View File

@ -38,10 +38,17 @@ This package is an internal implementation of the .NET Core SDK and is not meant
<!-- Reference implementation assemblies in addition to ref assemblies to get xml docs -->
<ReferenceImplementationAssemblies>true</ReferenceImplementationAssemblies>
<!-- We are ignoring MSB3243 warnings since implemenation and reference assemblies are versioned differently. We need both to compose the targeting pack with reference assemblies and xml docs. -->
<MSBuildWarningsAsMessages>MSB3243</MSBuildWarningsAsMessages >
<!-- Platform manifest data -->
<FrameworkListFileName>FrameworkList.xml</FrameworkListFileName>
<FrameworkListOutputPath>$(ArtifactsObjDir)$(FrameworkListFileName)</FrameworkListOutputPath>
<!-- Platform manifest and package override metatdata -->
<ReferencePackSharedFxVersion>$(AspNetCoreMajorVersion).$(AspNetCoreMinorVersion).0</ReferencePackSharedFxVersion>
<ReferencePackSharedFxVersion Condition="'$(VersionSuffix)' != ''">$(ReferencePackSharedFxVersion)-$(VersionSuffix)</ReferencePackSharedFxVersion>
<ReferencePlatformManifestOutputPath>$(ArtifactsObjDir)ref\PlatformManifest.txt</ReferencePlatformManifestOutputPath>
</PropertyGroup>
<ItemGroup>
@ -80,7 +87,7 @@ This package is an internal implementation of the .NET Core SDK and is not meant
</BuildDependsOn>
<!-- No-op when in source build -->
<BuildDependsOn Condition="'$(IsTargetingPackBuilding)' != 'false' and '$(DotNetBuildFromSource)' == 'true'"/>
<BuildDependsOn Condition="'$(IsTargetingPackBuilding)' == 'false'"/>
</PropertyGroup>
<!-- Override the default MSBuild targets so that nothing is returned from the project since it represents a collection of assemblies. -->
@ -95,6 +102,7 @@ This package is an internal implementation of the .NET Core SDK and is not meant
<!-- This target finds the reference assemblies. -->
<Target Name="_ResolveTargetingPackContent"
Returns="@(AspNetCoreReferenceAssemblyPath)"
BeforeTargets="_GetPackageFiles"
DependsOnTargets="ResolveReferences;FindReferenceAssembliesForReferences">
<ItemGroup>
@ -111,6 +119,7 @@ This package is an internal implementation of the .NET Core SDK and is not meant
Exclude="
@(_SelectedExtensionsRefAssemblies);
@(ReferencePathWithRefAssemblies->WithMetadataValue('NuGetPackageId', 'Microsoft.NETCore.App.Ref'));
@(ReferencePathWithRefAssemblies->WithMetadataValue('IsReferenceAssembly', 'false'));
@(ReferencePathWithRefAssemblies->WithMetadataValue('ReferenceGrouping', 'Microsoft.NETCore.App'));" />
<AspNetCoreReferenceAssemblyPath
@ -118,11 +127,23 @@ This package is an internal implementation of the .NET Core SDK and is not meant
<AspNetCoreReferenceDocXml Include="@(_ResolvedProjectReferencePaths->WithMetadataValue('IsReferenceAssembly', 'false')->'%(RootDir)%(Directory)%(FileName).xml')" />
<AspNetCoreReferenceDocXml Include="@(_SelectedExtensionsRefAssemblies->'$(MicrosoftInternalExtensionsRefsPath)%(FileName).xml')" />
</ItemGroup>
<RepoTasks.GenerateSharedFrameworkDepsFile
DepsFilePath="$(ProjectDepsFilePath)"
TargetFramework="$(TargetFramework)"
FrameworkName="$(TargetingPackName)"
FrameworkVersion="$(ReferencePackSharedFxVersion)"
References="@(AspNetCoreReferenceAssemblyPath)"
RuntimeIdentifier="$(TargetRuntimeIdentifier)"
RuntimePackageName="$(PackageId)"
PlatformManifestOutputPath="$(ReferencePlatformManifestOutputPath)" />
<ItemGroup>
<RefPackContent Include="@(AspNetCoreReferenceAssemblyPath)" PackagePath="$(RefAssemblyPackagePath)" />
<RefPackContent Include="@(AspNetCoreReferenceDocXml)" PackagePath="$(RefAssemblyPackagePath)" />
<RefPackContent Include="$(TargetDir)$(PackageConflictManifestFileName)" PackagePath="$(ManifestsPackagePath)" />
<RefPackContent Include="$(PlatformManifestOutputPath)" PackagePath="$(ManifestsPackagePath)" />
<RefPackContent Include="$(ReferencePlatformManifestOutputPath)" PackagePath="$(ManifestsPackagePath)" />
</ItemGroup>
</Target>
@ -130,9 +151,10 @@ This package is an internal implementation of the .NET Core SDK and is not meant
DependsOnTargets="ResolveReferences"
Inputs="$(MSBuildAllProjects)"
Outputs="$(TargetDir)$(PackageConflictManifestFileName)">
<ItemGroup>
<_AspNetCoreAppPackageOverrides Include="@(ReferencePath->'%(NuGetPackageId)|%(NuGetPackageVersion)')" Condition=" '%(ReferencePath.NuGetPackageId)' != 'Microsoft.NETCore.App' AND '%(ReferencePath.NuGetSourceType)' == 'Package' " />
<_AspNetCoreAppPackageOverrides Include="@(ReferencePath->'%(FileName)|$(SharedFxVersion)')" Condition=" '%(ReferencePath.ReferenceSourceTarget)' == 'ProjectReference' " />
<_AspNetCoreAppPackageOverrides Include="@(ReferencePath->'%(FileName)|$(ReferencePackSharedFxVersion)')" Condition=" '%(ReferencePath.ReferenceSourceTarget)' == 'ProjectReference' AND '%(ReferencePath.IsReferenceAssembly)' == 'true' " />
</ItemGroup>
<WriteLinesToFile

View File

@ -53,6 +53,13 @@
</ItemGroup>
<Target Name="GenerateTestData" BeforeTargets="GetAssemblyAttributes" DependsOnTargets="InitializeSourceControlInformation">
<!-- Use the ref pack logic to compute the list of expected targeting pack content -->
<MSBuild Projects="$(RepoRoot)src\Framework\ref\Microsoft.AspNetCore.App.Ref.csproj"
Targets="_ResolveTargetingPackContent"
SkipNonexistentProjects="false">
<Output TaskParameter="TargetOutputs" ItemName="_TargetingPackDependencies" />
</MSBuild>
<!-- This target is defined in eng/targets/Packaging.targets and included in every C# and F# project. -->
<MSBuild Projects="$(RepoRoot)src\Framework\src\Microsoft.AspNetCore.App.Runtime.csproj"
Targets="_GetPackageVersionInfo"
@ -68,6 +75,11 @@
</MSBuild>
<ItemGroup>
<AssemblyAttribute Include="Microsoft.AspNetCore.TestData">
<_Parameter1>TargetingPackDependencies</_Parameter1>
<_Parameter2>@(_TargetingPackDependencies)</_Parameter2>
</AssemblyAttribute>
<AssemblyAttribute Include="Microsoft.AspNetCore.TestData">
<_Parameter1>RepositoryCommit</_Parameter1>
<_Parameter2>$(SourceRevisionId)</_Parameter2>

View File

@ -59,8 +59,15 @@ namespace Microsoft.AspNetCore
public void PlatformManifestListsAllFiles()
{
var platformManifestPath = Path.Combine(_targetingPackRoot, "data", "PlatformManifest.txt");
var expectedAssemblies = TestData.GetSharedFxDependencies()
var expectedAssemblies = TestData.GetTargetingPackDependencies()
.Split(';', StringSplitOptions.RemoveEmptyEntries)
.Select(i =>
{
var fileName = Path.GetFileName(i);
return fileName.EndsWith(".dll", StringComparison.Ordinal)
? fileName.Substring(0, fileName.Length - 4)
: fileName;
})
.ToHashSet();
_output.WriteLine("==== file contents ====");

View File

@ -18,6 +18,8 @@ namespace Microsoft.AspNetCore
public static string GetSharedFxDependencies() => GetTestDataValue("SharedFxDependencies");
public static string GetTargetingPackDependencies() => GetTestDataValue("TargetingPackDependencies");
public static string GetTestDataValue(string key)
=> typeof(TestData).Assembly.GetCustomAttributes<TestDataAttribute>().Single(d => d.Key == key).Value;
}

View File

@ -46,7 +46,7 @@ namespace Microsoft.AspNetCore.Hosting.StaticWebAssets
}
else
{
return InnerProvider.GetDirectoryContents(physicalPath);
return InnerProvider.GetDirectoryContents(physicalPath.Value);
}
}
@ -59,7 +59,7 @@ namespace Microsoft.AspNetCore.Hosting.StaticWebAssets
}
else
{
return InnerProvider.GetFileInfo(physicalPath);
return InnerProvider.GetFileInfo(physicalPath.Value);
}
}

View File

@ -9,6 +9,7 @@
<Compile Include="$(SharedSourceRoot)EventSource.Testing\TestEventListener.cs" />
<Compile Include="$(SharedSourceRoot)EventSource.Testing\TestCounterListener.cs" />
<Content Include="testroot\**\*" CopyToOutputDirectory="PreserveNewest" CopyToPublishDirectory="PreserveNewest" />
<None Remove="testroot\wwwroot\Static Web Assets.txt" />
<Content Include="Microsoft.AspNetCore.Hosting.StaticWebAssets.xml" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>

View File

@ -37,6 +37,17 @@ namespace Microsoft.AspNetCore.Hosting.StaticWebAssets
Assert.Equal("/_content", provider.BasePath);
}
[Fact]
public void StaticWebAssetsFileProvider_FindsFileWithSpaces()
{
// Arrange & Act
var provider = new StaticWebAssetsFileProvider("/_content",
Path.Combine(AppContext.BaseDirectory, "testroot", "wwwroot"));
// Assert
Assert.True(provider.GetFileInfo("/_content/Static Web Assets.txt").Exists);
}
[Fact]
public void GetFileInfo_DoesNotMatch_IncompletePrefixSegments()
{

View File

@ -0,0 +1 @@
This file is here to validate that the static web assets file provider respect spaces.

Some files were not shown because too many files have changed in this diff Show More