Merge pull request #15355 from aspnet/prkrishn/merge-release
Merge release/3.1
This commit is contained in:
commit
ec8304ae85
|
|
@ -19,4 +19,4 @@
|
||||||
/src/Servers/ @tratcher @jkotalik @anurse @halter73
|
/src/Servers/ @tratcher @jkotalik @anurse @halter73
|
||||||
/src/Middleware/Rewrite @jkotalik @anurse
|
/src/Middleware/Rewrite @jkotalik @anurse
|
||||||
/src/Middleware/HttpsPolicy @jkotalik @anurse
|
/src/Middleware/HttpsPolicy @jkotalik @anurse
|
||||||
/src/SignalR/ @mikaelm12 @BrennanConroy @halter73 @anurse
|
/src/SignalR/ @BrennanConroy @halter73 @anurse
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
<ProjectReferenceProvider Include="GetDocument.Insider" ProjectPath="$(RepoRoot)src\Tools\GetDocumentInsider\src\GetDocumentInsider.csproj" />
|
<ProjectReferenceProvider Include="GetDocument.Insider" ProjectPath="$(RepoRoot)src\Tools\GetDocumentInsider\src\GetDocumentInsider.csproj" />
|
||||||
<ProjectReferenceProvider Include="Microsoft.AspNetCore.SignalR.Specification.Tests" ProjectPath="$(RepoRoot)src\SignalR\server\Specification.Tests\src\Microsoft.AspNetCore.SignalR.Specification.Tests.csproj" />
|
<ProjectReferenceProvider Include="Microsoft.AspNetCore.SignalR.Specification.Tests" ProjectPath="$(RepoRoot)src\SignalR\server\Specification.Tests\src\Microsoft.AspNetCore.SignalR.Specification.Tests.csproj" />
|
||||||
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Blazor.Build" ProjectPath="$(RepoRoot)src\Components\Blazor\Build\src\Microsoft.AspNetCore.Blazor.Build.csproj" />
|
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Blazor.Build" ProjectPath="$(RepoRoot)src\Components\Blazor\Build\src\Microsoft.AspNetCore.Blazor.Build.csproj" />
|
||||||
|
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Blazor.DataAnnotations.Validation" ProjectPath="$(RepoRoot)src\Components\Blazor\Validation\src\Microsoft.AspNetCore.Blazor.DataAnnotations.Validation.csproj" />
|
||||||
<ProjectReferenceProvider Include="Ignitor" ProjectPath="$(RepoRoot)src\Components\Ignitor\src\Ignitor.csproj" />
|
<ProjectReferenceProvider Include="Ignitor" ProjectPath="$(RepoRoot)src\Components\Ignitor\src\Ignitor.csproj" />
|
||||||
<ProjectReferenceProvider Include="BlazorServerApp" ProjectPath="$(RepoRoot)src\Components\Samples\BlazorServerApp\BlazorServerApp.csproj" />
|
<ProjectReferenceProvider Include="BlazorServerApp" ProjectPath="$(RepoRoot)src\Components\Samples\BlazorServerApp\BlazorServerApp.csproj" />
|
||||||
<ProjectReferenceProvider Include="Microsoft.AspNetCore" ProjectPath="$(RepoRoot)src\DefaultBuilder\src\Microsoft.AspNetCore.csproj" RefProjectPath="$(RepoRoot)src\DefaultBuilder\ref\Microsoft.AspNetCore.csproj" />
|
<ProjectReferenceProvider Include="Microsoft.AspNetCore" ProjectPath="$(RepoRoot)src\DefaultBuilder\src\Microsoft.AspNetCore.csproj" RefProjectPath="$(RepoRoot)src\DefaultBuilder\ref\Microsoft.AspNetCore.csproj" />
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
|
|
@ -89,19 +91,26 @@ namespace Microsoft.AspNetCore.Builder
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|
||||||
await context.Response.WriteAsync($@"
|
await context.Response.WriteAsync($@"
|
||||||
<h1>Unable to find debuggable browser tab</h1>
|
<h1>Unable to find debuggable browser tab</h1>
|
||||||
<p>
|
<p>
|
||||||
Could not get a list of browser tabs from <code>{debuggerTabsListUrl}</code>.
|
Could not get a list of browser tabs from <code>{debuggerTabsListUrl}</code>.
|
||||||
Ensure Chrome is running with debugging enabled.
|
Ensure your browser is running with debugging enabled.
|
||||||
</p>
|
</p>
|
||||||
<h2>Resolution</h2>
|
<h2>Resolution</h2>
|
||||||
|
<p>
|
||||||
|
<h4>If you are using Google Chrome for your development, follow these instructions:</h4>
|
||||||
{GetLaunchChromeInstructions(appRootUrl)}
|
{GetLaunchChromeInstructions(appRootUrl)}
|
||||||
<p>... then use that new tab for debugging.</p>
|
</p>
|
||||||
|
<p>
|
||||||
|
<h4>If you are using Microsoft Edge (Chromium) for your development, follow these instructions:</h4>
|
||||||
|
{GetLaunchEdgeInstructions(appRootUrl)}
|
||||||
|
</p>
|
||||||
|
<strong>This should launch a new browser window with debugging enabled..</p>
|
||||||
<h2>Underlying exception:</h2>
|
<h2>Underlying exception:</h2>
|
||||||
<pre>{ex}</pre>
|
<pre>{ex}</pre>
|
||||||
");
|
");
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -144,20 +153,42 @@ namespace Microsoft.AspNetCore.Builder
|
||||||
|
|
||||||
private static string GetLaunchChromeInstructions(string appRootUrl)
|
private static string GetLaunchChromeInstructions(string appRootUrl)
|
||||||
{
|
{
|
||||||
|
var profilePath = Path.Combine(Path.GetTempPath(), "blazor-edge-debug");
|
||||||
|
|
||||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||||
{
|
{
|
||||||
return $@"<p>Close all Chrome instances, then press Win+R and enter the following:</p>
|
return $@"<p>Press Win+R and enter the following:</p>
|
||||||
<p><strong><code>""%programfiles(x86)%\Google\Chrome\Application\chrome.exe"" --remote-debugging-port=9222 {appRootUrl}</code></strong></p>";
|
<p><strong><code>chrome --remote-debugging-port=9222 --user-data-dir=""{profilePath}"" {appRootUrl}</code></strong></p>";
|
||||||
}
|
}
|
||||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||||
{
|
{
|
||||||
return $@"<p>Close all Chrome instances, then in a terminal window execute the following:</p>
|
return $@"<p>In a terminal window execute the following:</p>
|
||||||
<p><strong><code>google-chrome --remote-debugging-port=9222 {appRootUrl}</code></strong></p>";
|
<p><strong><code>google-chrome --remote-debugging-port=9222 --user-data-dir={profilePath} {appRootUrl}</code></strong></p>";
|
||||||
}
|
}
|
||||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
||||||
{
|
{
|
||||||
return $@"<p>Close all Chrome instances, then in a terminal window execute the following:</p>
|
return $@"<p>Execute the following:</p>
|
||||||
<p><strong><code>open /Applications/Google\ Chrome.app --args --remote-debugging-port=9222 {appRootUrl}</code></strong></p>";
|
<p><strong><code>open /Applications/Google\ Chrome.app --args --remote-debugging-port=9222 --user-data-dir={profilePath} {appRootUrl}</code></strong></p>";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Unknown OS platform");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetLaunchEdgeInstructions(string appRootUrl)
|
||||||
|
{
|
||||||
|
var profilePath = Path.Combine(Path.GetTempPath(), "blazor-chrome-debug");
|
||||||
|
|
||||||
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||||
|
{
|
||||||
|
return $@"<p>Press Win+R and enter the following:</p>
|
||||||
|
<p><strong><code>msedge --remote-debugging-port=9222 --user-data-dir=""{profilePath}"" {appRootUrl}</code></strong></p>";
|
||||||
|
}
|
||||||
|
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
||||||
|
{
|
||||||
|
return $@"<p>In a terminal window execute the following:</p>
|
||||||
|
<p><strong><code>open /Applications/Microsoft\ Edge\ Dev.app --args --remote-debugging-port=9222 --user-data-dir={profilePath} {appRootUrl}</code></strong></p>";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
<span class="text-nowrap">
|
<span class="text-nowrap">
|
||||||
Please take our
|
Please take our
|
||||||
<a target="_blank" class="font-weight-bold" href="https://go.microsoft.com/fwlink/?linkid=2100553">brief survey</a>
|
<a target="_blank" class="font-weight-bold" href="https://go.microsoft.com/fwlink/?linkid=2109206">brief survey</a>
|
||||||
</span>
|
</span>
|
||||||
and tell us what you think.
|
and tell us what you think.
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,16 @@ html, body {
|
||||||
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
a, .btn-link {
|
||||||
|
color: #0366d6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary {
|
||||||
|
color: #fff;
|
||||||
|
background-color: #1b6ec2;
|
||||||
|
border-color: #1861ac;
|
||||||
|
}
|
||||||
|
|
||||||
app {
|
app {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
@ -21,8 +31,19 @@ app {
|
||||||
}
|
}
|
||||||
|
|
||||||
.main .top-row {
|
.main .top-row {
|
||||||
background-color: #e6e6e6;
|
background-color: #f7f7f7;
|
||||||
border-bottom: 1px solid #d6d5d5;
|
border-bottom: 1px solid #d6d5d5;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main .top-row > a, .main .top-row .btn-link {
|
||||||
|
white-space: nowrap;
|
||||||
|
margin-left: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main .top-row a:first-child {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar {
|
.sidebar {
|
||||||
|
|
@ -44,20 +65,20 @@ app {
|
||||||
top: -2px;
|
top: -2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-item {
|
.sidebar .nav-item {
|
||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
padding-bottom: 0.5rem;
|
padding-bottom: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-item:first-of-type {
|
.sidebar .nav-item:first-of-type {
|
||||||
padding-top: 1rem;
|
padding-top: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-item:last-of-type {
|
.sidebar .nav-item:last-of-type {
|
||||||
padding-bottom: 1rem;
|
padding-bottom: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-item a {
|
.sidebar .nav-item a {
|
||||||
color: #d7d7d7;
|
color: #d7d7d7;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
height: 3rem;
|
height: 3rem;
|
||||||
|
|
@ -66,12 +87,12 @@ app {
|
||||||
line-height: 3rem;
|
line-height: 3rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-item a.active {
|
.sidebar .nav-item a.active {
|
||||||
background-color: rgba(255,255,255,0.25);
|
background-color: rgba(255,255,255,0.25);
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-item a:hover {
|
.sidebar .nav-item a:hover {
|
||||||
background-color: rgba(255,255,255,0.1);
|
background-color: rgba(255,255,255,0.1);
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
@ -116,9 +137,17 @@ app {
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 767.98px) {
|
@media (max-width: 767.98px) {
|
||||||
.main .top-row {
|
.main .top-row:not(.auth) {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.main .top-row.auth {
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main .top-row a, .main .top-row .btn-link {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width: 768px) {
|
@media (min-width: 768px) {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
namespace System.ComponentModel.DataAnnotations
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A <see cref="ValidationAttribute"/> that compares two properties
|
||||||
|
/// </summary>
|
||||||
|
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
|
||||||
|
public sealed class ComparePropertyAttribute : CompareAttribute
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of <see cref="BlazorCompareAttribute"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="otherProperty">The property to compare with the current property.</param>
|
||||||
|
public ComparePropertyAttribute(string otherProperty)
|
||||||
|
: base(otherProperty)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
|
||||||
|
{
|
||||||
|
var validationResult = base.IsValid(value, validationContext);
|
||||||
|
if (validationResult == ValidationResult.Success)
|
||||||
|
{
|
||||||
|
return validationResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ValidationResult(validationResult.ErrorMessage, new[] { validationContext.MemberName });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
|
<Description>Provides experimental support for validation using DataAnnotations.</Description>
|
||||||
|
<IsShippingPackage>true</IsShippingPackage>
|
||||||
|
<HasReferenceAssembly>false</HasReferenceAssembly>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="Microsoft.AspNetCore.Components.Forms" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<InternalsVisibleTo Include="Microsoft.AspNetCore.Blazor.DataAnnotations.Validation.Tests" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
|
|
@ -0,0 +1,125 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Components.Forms
|
||||||
|
{
|
||||||
|
public class ObjectGraphDataAnnotationsValidator : ComponentBase
|
||||||
|
{
|
||||||
|
private static readonly object ValidationContextValidatorKey = new object();
|
||||||
|
private static readonly object ValidatedObjectsKey = new object();
|
||||||
|
private ValidationMessageStore _validationMessageStore;
|
||||||
|
|
||||||
|
[CascadingParameter]
|
||||||
|
internal EditContext EditContext { get; set; }
|
||||||
|
|
||||||
|
protected override void OnInitialized()
|
||||||
|
{
|
||||||
|
_validationMessageStore = new ValidationMessageStore(EditContext);
|
||||||
|
|
||||||
|
// Perform object-level validation (starting from the root model) on request
|
||||||
|
EditContext.OnValidationRequested += (sender, eventArgs) =>
|
||||||
|
{
|
||||||
|
_validationMessageStore.Clear();
|
||||||
|
ValidateObject(EditContext.Model, new HashSet<object>());
|
||||||
|
EditContext.NotifyValidationStateChanged();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Perform per-field validation on each field edit
|
||||||
|
EditContext.OnFieldChanged += (sender, eventArgs) =>
|
||||||
|
ValidateField(EditContext, _validationMessageStore, eventArgs.FieldIdentifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void ValidateObject(object value, HashSet<object> visited)
|
||||||
|
{
|
||||||
|
if (value is null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!visited.Add(value))
|
||||||
|
{
|
||||||
|
// Already visited this object.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value is IEnumerable<object> enumerable)
|
||||||
|
{
|
||||||
|
var index = 0;
|
||||||
|
foreach (var item in enumerable)
|
||||||
|
{
|
||||||
|
ValidateObject(item, visited);
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var validationResults = new List<ValidationResult>();
|
||||||
|
ValidateObject(value, visited, validationResults);
|
||||||
|
|
||||||
|
// Transfer results to the ValidationMessageStore
|
||||||
|
foreach (var validationResult in validationResults)
|
||||||
|
{
|
||||||
|
if (!validationResult.MemberNames.Any())
|
||||||
|
{
|
||||||
|
_validationMessageStore.Add(new FieldIdentifier(value, string.Empty), validationResult.ErrorMessage);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var memberName in validationResult.MemberNames)
|
||||||
|
{
|
||||||
|
var fieldIdentifier = new FieldIdentifier(value, memberName);
|
||||||
|
_validationMessageStore.Add(fieldIdentifier, validationResult.ErrorMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ValidateObject(object value, HashSet<object> visited, List<ValidationResult> validationResults)
|
||||||
|
{
|
||||||
|
var validationContext = new ValidationContext(value);
|
||||||
|
validationContext.Items.Add(ValidationContextValidatorKey, this);
|
||||||
|
validationContext.Items.Add(ValidatedObjectsKey, visited);
|
||||||
|
Validator.TryValidateObject(value, validationContext, validationResults, validateAllProperties: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static bool TryValidateRecursive(object value, ValidationContext validationContext)
|
||||||
|
{
|
||||||
|
if (validationContext.Items.TryGetValue(ValidationContextValidatorKey, out var result) && result is ObjectGraphDataAnnotationsValidator validator)
|
||||||
|
{
|
||||||
|
var visited = (HashSet<object>)validationContext.Items[ValidatedObjectsKey];
|
||||||
|
validator.ValidateObject(value, visited);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ValidateField(EditContext editContext, ValidationMessageStore messages, in FieldIdentifier fieldIdentifier)
|
||||||
|
{
|
||||||
|
// DataAnnotations only validates public properties, so that's all we'll look for
|
||||||
|
var propertyInfo = fieldIdentifier.Model.GetType().GetProperty(fieldIdentifier.FieldName);
|
||||||
|
if (propertyInfo != null)
|
||||||
|
{
|
||||||
|
var propertyValue = propertyInfo.GetValue(fieldIdentifier.Model);
|
||||||
|
var validationContext = new ValidationContext(fieldIdentifier.Model)
|
||||||
|
{
|
||||||
|
MemberName = propertyInfo.Name
|
||||||
|
};
|
||||||
|
var results = new List<ValidationResult>();
|
||||||
|
|
||||||
|
Validator.TryValidateProperty(propertyValue, validationContext, results);
|
||||||
|
messages.Clear(fieldIdentifier);
|
||||||
|
messages.Add(fieldIdentifier, results.Select(result => result.ErrorMessage));
|
||||||
|
|
||||||
|
// We have to notify even if there were no messages before and are still no messages now,
|
||||||
|
// because the "state" that changed might be the completion of some async validation task
|
||||||
|
editContext.NotifyValidationStateChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using Microsoft.AspNetCore.Components.Forms;
|
||||||
|
|
||||||
|
namespace System.ComponentModel.DataAnnotations
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A <see cref="ValidationAttribute"/> that indicates that the property is a complex or collection type that further needs to be validated.
|
||||||
|
/// <para>
|
||||||
|
/// By default <see cref="Validator"/> does not recurse in to complex property types during validation.
|
||||||
|
/// When used in conjunction with <see cref="ObjectGraphDataAnnotationsValidator"/>, this property allows the validation system to validate
|
||||||
|
/// complex or collection type properties.
|
||||||
|
/// </para>
|
||||||
|
/// </summary>
|
||||||
|
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
|
||||||
|
public sealed class ValidateComplexTypeAttribute : ValidationAttribute
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
|
||||||
|
{
|
||||||
|
if (!ObjectGraphDataAnnotationsValidator.TryValidateRecursive(value, validationContext))
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"{nameof(ValidateComplexTypeAttribute)} can only used with {nameof(ObjectGraphDataAnnotationsValidator)}.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return ValidationResult.Success;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="Microsoft.AspNetCore.Blazor.DataAnnotations.Validation" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
|
|
@ -0,0 +1,540 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.Linq;
|
||||||
|
using Microsoft.AspNetCore.Components.Forms;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Components
|
||||||
|
{
|
||||||
|
public class ObjectGraphDataAnnotationsValidatorTest
|
||||||
|
{
|
||||||
|
public class SimpleModel
|
||||||
|
{
|
||||||
|
[Required]
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
[Range(1, 16)]
|
||||||
|
public int Age { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ValidateObject_SimpleObject()
|
||||||
|
{
|
||||||
|
var model = new SimpleModel
|
||||||
|
{
|
||||||
|
Age = 23,
|
||||||
|
};
|
||||||
|
|
||||||
|
var editContext = Validate(model);
|
||||||
|
var messages = editContext.GetValidationMessages(() => model.Name);
|
||||||
|
Assert.Single(messages);
|
||||||
|
|
||||||
|
messages = editContext.GetValidationMessages(() => model.Age);
|
||||||
|
Assert.Single(messages);
|
||||||
|
|
||||||
|
Assert.Equal(2, editContext.GetValidationMessages().Count());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ValidateObject_SimpleObject_AllValid()
|
||||||
|
{
|
||||||
|
var model = new SimpleModel { Name = "Test", Age = 5 };
|
||||||
|
|
||||||
|
var editContext = Validate(model);
|
||||||
|
var messages = editContext.GetValidationMessages(() => model.Name);
|
||||||
|
Assert.Empty(messages);
|
||||||
|
|
||||||
|
messages = editContext.GetValidationMessages(() => model.Age);
|
||||||
|
Assert.Empty(messages);
|
||||||
|
|
||||||
|
Assert.Empty(editContext.GetValidationMessages());
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ModelWithComplexProperty
|
||||||
|
{
|
||||||
|
[Required]
|
||||||
|
public string Property1 { get; set; }
|
||||||
|
|
||||||
|
[ValidateComplexType]
|
||||||
|
public SimpleModel SimpleModel { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ValidateObject_NullComplexProperty()
|
||||||
|
{
|
||||||
|
var model = new ModelWithComplexProperty();
|
||||||
|
|
||||||
|
var editContext = Validate(model);
|
||||||
|
var messages = editContext.GetValidationMessages(() => model.Property1);
|
||||||
|
Assert.Single(messages);
|
||||||
|
|
||||||
|
Assert.Single(editContext.GetValidationMessages());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ValidateObject_ModelWithComplexProperties()
|
||||||
|
{
|
||||||
|
var model = new ModelWithComplexProperty { SimpleModel = new SimpleModel() };
|
||||||
|
|
||||||
|
var editContext = Validate(model);
|
||||||
|
var messages = editContext.GetValidationMessages(() => model.Property1);
|
||||||
|
Assert.Single(messages);
|
||||||
|
|
||||||
|
messages = editContext.GetValidationMessages(() => model.SimpleModel);
|
||||||
|
Assert.Empty(messages);
|
||||||
|
|
||||||
|
messages = editContext.GetValidationMessages(() => model.SimpleModel.Age);
|
||||||
|
Assert.Single(messages);
|
||||||
|
|
||||||
|
messages = editContext.GetValidationMessages(() => model.SimpleModel.Name);
|
||||||
|
Assert.Single(messages);
|
||||||
|
|
||||||
|
Assert.Equal(3, editContext.GetValidationMessages().Count());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ValidateObject_ModelWithComplexProperties_SomeValid()
|
||||||
|
{
|
||||||
|
var model = new ModelWithComplexProperty
|
||||||
|
{
|
||||||
|
Property1 = "Value",
|
||||||
|
SimpleModel = new SimpleModel { Name = "Some Value" },
|
||||||
|
};
|
||||||
|
|
||||||
|
var editContext = Validate(model);
|
||||||
|
var messages = editContext.GetValidationMessages(() => model.Property1);
|
||||||
|
Assert.Empty(messages);
|
||||||
|
|
||||||
|
messages = editContext.GetValidationMessages(() => model.SimpleModel);
|
||||||
|
Assert.Empty(messages);
|
||||||
|
|
||||||
|
messages = editContext.GetValidationMessages(() => model.SimpleModel.Age);
|
||||||
|
Assert.Single(messages);
|
||||||
|
|
||||||
|
messages = editContext.GetValidationMessages(() => model.SimpleModel.Name);
|
||||||
|
Assert.Empty(messages);
|
||||||
|
|
||||||
|
Assert.Single(editContext.GetValidationMessages());
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TestValidatableObject : IValidatableObject
|
||||||
|
{
|
||||||
|
[Required]
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
|
||||||
|
{
|
||||||
|
yield return new ValidationResult("Custom validation error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ModelWithValidatableComplexProperty
|
||||||
|
{
|
||||||
|
[Required]
|
||||||
|
public string Property1 { get; set; }
|
||||||
|
|
||||||
|
[ValidateComplexType]
|
||||||
|
public TestValidatableObject Property2 { get; set; } = new TestValidatableObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ValidateObject_ValidatableComplexProperty()
|
||||||
|
{
|
||||||
|
var model = new ModelWithValidatableComplexProperty();
|
||||||
|
|
||||||
|
var editContext = Validate(model);
|
||||||
|
var messages = editContext.GetValidationMessages(() => model.Property1);
|
||||||
|
Assert.Single(messages);
|
||||||
|
|
||||||
|
messages = editContext.GetValidationMessages(() => model.Property2);
|
||||||
|
Assert.Empty(messages);
|
||||||
|
|
||||||
|
messages = editContext.GetValidationMessages(() => model.Property2.Name);
|
||||||
|
Assert.Single(messages);
|
||||||
|
|
||||||
|
Assert.Equal(2, editContext.GetValidationMessages().Count());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ValidateObject_ValidatableComplexProperty_ValidatesIValidatableProperty()
|
||||||
|
{
|
||||||
|
var model = new ModelWithValidatableComplexProperty
|
||||||
|
{
|
||||||
|
Property2 = new TestValidatableObject { Name = "test" },
|
||||||
|
};
|
||||||
|
|
||||||
|
var editContext = Validate(model);
|
||||||
|
var messages = editContext.GetValidationMessages(() => model.Property1);
|
||||||
|
Assert.Single(messages);
|
||||||
|
|
||||||
|
messages = editContext.GetValidationMessages(new FieldIdentifier(model.Property2, string.Empty));
|
||||||
|
Assert.Single(messages);
|
||||||
|
|
||||||
|
messages = editContext.GetValidationMessages(() => model.Property2.Name);
|
||||||
|
Assert.Empty(messages);
|
||||||
|
|
||||||
|
Assert.Equal(2, editContext.GetValidationMessages().Count());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ValidateObject_ModelIsIValidatable_PropertyHasError()
|
||||||
|
{
|
||||||
|
var model = new TestValidatableObject();
|
||||||
|
|
||||||
|
var editContext = Validate(model);
|
||||||
|
var messages = editContext.GetValidationMessages(new FieldIdentifier(model, string.Empty));
|
||||||
|
Assert.Empty(messages);
|
||||||
|
|
||||||
|
messages = editContext.GetValidationMessages(() => model.Name);
|
||||||
|
Assert.Single(messages);
|
||||||
|
|
||||||
|
Assert.Single(editContext.GetValidationMessages());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ValidateObject_ModelIsIValidatable_ModelHasError()
|
||||||
|
{
|
||||||
|
var model = new TestValidatableObject { Name = "test" };
|
||||||
|
|
||||||
|
var editContext = Validate(model);
|
||||||
|
var messages = editContext.GetValidationMessages(new FieldIdentifier(model, string.Empty));
|
||||||
|
Assert.Single(messages);
|
||||||
|
|
||||||
|
messages = editContext.GetValidationMessages(() => model.Name);
|
||||||
|
Assert.Empty(messages);
|
||||||
|
|
||||||
|
Assert.Single(editContext.GetValidationMessages());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ValidateObject_CollectionModel()
|
||||||
|
{
|
||||||
|
var model = new List<SimpleModel>
|
||||||
|
{
|
||||||
|
new SimpleModel(),
|
||||||
|
new SimpleModel { Name = "test", },
|
||||||
|
};
|
||||||
|
|
||||||
|
var editContext = Validate(model);
|
||||||
|
|
||||||
|
var item = model[0];
|
||||||
|
var messages = editContext.GetValidationMessages(new FieldIdentifier(model, "0"));
|
||||||
|
Assert.Empty(messages);
|
||||||
|
|
||||||
|
messages = editContext.GetValidationMessages(() => item.Name);
|
||||||
|
Assert.Single(messages);
|
||||||
|
|
||||||
|
messages = editContext.GetValidationMessages(() => item.Age);
|
||||||
|
Assert.Single(messages);
|
||||||
|
|
||||||
|
item = model[1];
|
||||||
|
messages = editContext.GetValidationMessages(new FieldIdentifier(model, "1"));
|
||||||
|
Assert.Empty(messages);
|
||||||
|
|
||||||
|
messages = editContext.GetValidationMessages(() => item.Name);
|
||||||
|
Assert.Empty(messages);
|
||||||
|
|
||||||
|
messages = editContext.GetValidationMessages(() => item.Age);
|
||||||
|
Assert.Single(messages);
|
||||||
|
|
||||||
|
Assert.Equal(3, editContext.GetValidationMessages().Count());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ValidateObject_CollectionValidatableModel()
|
||||||
|
{
|
||||||
|
var model = new List<TestValidatableObject>
|
||||||
|
{
|
||||||
|
new TestValidatableObject(),
|
||||||
|
new TestValidatableObject { Name = "test", },
|
||||||
|
};
|
||||||
|
|
||||||
|
var editContext = Validate(model);
|
||||||
|
|
||||||
|
var item = model[0];
|
||||||
|
var messages = editContext.GetValidationMessages(() => item.Name);
|
||||||
|
Assert.Single(messages);
|
||||||
|
|
||||||
|
item = model[1];
|
||||||
|
Assert.Single(messages);
|
||||||
|
|
||||||
|
messages = editContext.GetValidationMessages(() => item.Name);
|
||||||
|
Assert.Empty(messages);
|
||||||
|
|
||||||
|
Assert.Equal(2, editContext.GetValidationMessages().Count());
|
||||||
|
}
|
||||||
|
|
||||||
|
private class Level1Validation
|
||||||
|
{
|
||||||
|
[ValidateComplexType]
|
||||||
|
public Level2Validation Level2 { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Level2Validation
|
||||||
|
{
|
||||||
|
[ValidateComplexType]
|
||||||
|
public SimpleModel Level3 { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ValidateObject_ManyLevels()
|
||||||
|
{
|
||||||
|
var model = new Level1Validation
|
||||||
|
{
|
||||||
|
Level2 = new Level2Validation
|
||||||
|
{
|
||||||
|
Level3 = new SimpleModel
|
||||||
|
{
|
||||||
|
Age = 47,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var editContext = Validate(model);
|
||||||
|
var level3 = model.Level2.Level3;
|
||||||
|
|
||||||
|
var messages = editContext.GetValidationMessages(() => level3.Name);
|
||||||
|
Assert.Single(messages);
|
||||||
|
|
||||||
|
messages = editContext.GetValidationMessages(() => level3.Age);
|
||||||
|
Assert.Single(messages);
|
||||||
|
|
||||||
|
Assert.Equal(2, editContext.GetValidationMessages().Count());
|
||||||
|
}
|
||||||
|
|
||||||
|
private class Person
|
||||||
|
{
|
||||||
|
[Required]
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
[ValidateComplexType]
|
||||||
|
public Person Related { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ValidateObject_RecursiveRelation()
|
||||||
|
{
|
||||||
|
var model = new Person { Related = new Person() };
|
||||||
|
model.Related.Related = model;
|
||||||
|
|
||||||
|
var editContext = Validate(model);
|
||||||
|
|
||||||
|
var messages = editContext.GetValidationMessages(() => model.Name);
|
||||||
|
Assert.Single(messages);
|
||||||
|
|
||||||
|
messages = editContext.GetValidationMessages(() => model.Related.Name);
|
||||||
|
Assert.Single(messages);
|
||||||
|
|
||||||
|
Assert.Equal(2, editContext.GetValidationMessages().Count());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ValidateObject_RecursiveRelation_OverManySteps()
|
||||||
|
{
|
||||||
|
var person1 = new Person();
|
||||||
|
var person2 = new Person { Name = "Valid name" };
|
||||||
|
var person3 = new Person();
|
||||||
|
var person4 = new Person();
|
||||||
|
|
||||||
|
person1.Related = person2;
|
||||||
|
person2.Related = person3;
|
||||||
|
person3.Related = person4;
|
||||||
|
person4.Related = person1;
|
||||||
|
|
||||||
|
var editContext = Validate(person1);
|
||||||
|
|
||||||
|
var messages = editContext.GetValidationMessages(() => person1.Name);
|
||||||
|
Assert.Single(messages);
|
||||||
|
|
||||||
|
messages = editContext.GetValidationMessages(() => person2.Name);
|
||||||
|
Assert.Empty(messages);
|
||||||
|
|
||||||
|
messages = editContext.GetValidationMessages(() => person3.Name);
|
||||||
|
Assert.Single(messages);
|
||||||
|
|
||||||
|
messages = editContext.GetValidationMessages(() => person4.Name);
|
||||||
|
Assert.Single(messages);
|
||||||
|
|
||||||
|
Assert.Equal(3, editContext.GetValidationMessages().Count());
|
||||||
|
}
|
||||||
|
|
||||||
|
private class Node
|
||||||
|
{
|
||||||
|
[Required]
|
||||||
|
public string Id { get; set; }
|
||||||
|
|
||||||
|
[ValidateComplexType]
|
||||||
|
public List<Node> Related { get; set; } = new List<Node>();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ValidateObject_RecursiveRelation_ViaCollection()
|
||||||
|
{
|
||||||
|
var node1 = new Node();
|
||||||
|
var node2 = new Node { Id = "Valid Id" };
|
||||||
|
var node3 = new Node();
|
||||||
|
node1.Related.Add(node2);
|
||||||
|
node2.Related.Add(node3);
|
||||||
|
node3.Related.Add(node1);
|
||||||
|
|
||||||
|
var editContext = Validate(node1);
|
||||||
|
|
||||||
|
var messages = editContext.GetValidationMessages(() => node1.Id);
|
||||||
|
Assert.Single(messages);
|
||||||
|
|
||||||
|
messages = editContext.GetValidationMessages(() => node2.Id);
|
||||||
|
Assert.Empty(messages);
|
||||||
|
|
||||||
|
messages = editContext.GetValidationMessages(() => node3.Id);
|
||||||
|
Assert.Single(messages);
|
||||||
|
|
||||||
|
Assert.Equal(2, editContext.GetValidationMessages().Count());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ValidateObject_RecursiveRelation_InCollection()
|
||||||
|
{
|
||||||
|
var person1 = new Person();
|
||||||
|
var person2 = new Person { Name = "Valid name" };
|
||||||
|
var person3 = new Person();
|
||||||
|
var person4 = new Person();
|
||||||
|
|
||||||
|
person1.Related = person2;
|
||||||
|
person2.Related = person3;
|
||||||
|
person3.Related = person4;
|
||||||
|
person4.Related = person1;
|
||||||
|
|
||||||
|
var editContext = Validate(person1);
|
||||||
|
|
||||||
|
var messages = editContext.GetValidationMessages(() => person1.Name);
|
||||||
|
Assert.Single(messages);
|
||||||
|
|
||||||
|
messages = editContext.GetValidationMessages(() => person2.Name);
|
||||||
|
Assert.Empty(messages);
|
||||||
|
|
||||||
|
messages = editContext.GetValidationMessages(() => person3.Name);
|
||||||
|
Assert.Single(messages);
|
||||||
|
|
||||||
|
messages = editContext.GetValidationMessages(() => person4.Name);
|
||||||
|
Assert.Single(messages);
|
||||||
|
|
||||||
|
Assert.Equal(3, editContext.GetValidationMessages().Count());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ValidateField_PropertyValid()
|
||||||
|
{
|
||||||
|
var model = new SimpleModel { Age = 1 };
|
||||||
|
var fieldIdentifier = FieldIdentifier.Create(() => model.Age);
|
||||||
|
|
||||||
|
var editContext = ValidateField(model, fieldIdentifier);
|
||||||
|
var messages = editContext.GetValidationMessages(fieldIdentifier);
|
||||||
|
Assert.Empty(messages);
|
||||||
|
|
||||||
|
Assert.Empty(editContext.GetValidationMessages());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ValidateField_PropertyInvalid()
|
||||||
|
{
|
||||||
|
var model = new SimpleModel { Age = 42 };
|
||||||
|
var fieldIdentifier = FieldIdentifier.Create(() => model.Age);
|
||||||
|
|
||||||
|
var editContext = ValidateField(model, fieldIdentifier);
|
||||||
|
var messages = editContext.GetValidationMessages(fieldIdentifier);
|
||||||
|
Assert.Single(messages);
|
||||||
|
|
||||||
|
Assert.Single(editContext.GetValidationMessages());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ValidateField_AfterSubmitValidation()
|
||||||
|
{
|
||||||
|
var model = new SimpleModel { Age = 42 };
|
||||||
|
var fieldIdentifier = FieldIdentifier.Create(() => model.Age);
|
||||||
|
|
||||||
|
var editContext = Validate(model);
|
||||||
|
var messages = editContext.GetValidationMessages(fieldIdentifier);
|
||||||
|
Assert.Single(messages);
|
||||||
|
|
||||||
|
Assert.Equal(2, editContext.GetValidationMessages().Count());
|
||||||
|
|
||||||
|
model.Age = 4;
|
||||||
|
|
||||||
|
editContext.NotifyFieldChanged(fieldIdentifier);
|
||||||
|
messages = editContext.GetValidationMessages(fieldIdentifier);
|
||||||
|
Assert.Empty(messages);
|
||||||
|
|
||||||
|
Assert.Single(editContext.GetValidationMessages());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ValidateField_ModelWithComplexProperty()
|
||||||
|
{
|
||||||
|
var model = new ModelWithComplexProperty
|
||||||
|
{
|
||||||
|
SimpleModel = new SimpleModel { Age = 1 },
|
||||||
|
};
|
||||||
|
var fieldIdentifier = FieldIdentifier.Create(() => model.SimpleModel.Name);
|
||||||
|
|
||||||
|
var editContext = ValidateField(model, fieldIdentifier);
|
||||||
|
var messages = editContext.GetValidationMessages(fieldIdentifier);
|
||||||
|
Assert.Single(messages);
|
||||||
|
|
||||||
|
Assert.Single(editContext.GetValidationMessages());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ValidateField_ModelWithComplexProperty_AfterSubmitValidation()
|
||||||
|
{
|
||||||
|
var model = new ModelWithComplexProperty
|
||||||
|
{
|
||||||
|
Property1 = "test",
|
||||||
|
SimpleModel = new SimpleModel { Age = 29, Name = "Test" },
|
||||||
|
};
|
||||||
|
var fieldIdentifier = FieldIdentifier.Create(() => model.SimpleModel.Age);
|
||||||
|
|
||||||
|
var editContext = Validate(model);
|
||||||
|
var messages = editContext.GetValidationMessages(fieldIdentifier);
|
||||||
|
Assert.Single(messages);
|
||||||
|
|
||||||
|
model.SimpleModel.Age = 9;
|
||||||
|
editContext.NotifyFieldChanged(fieldIdentifier);
|
||||||
|
|
||||||
|
messages = editContext.GetValidationMessages(fieldIdentifier);
|
||||||
|
Assert.Empty(messages);
|
||||||
|
Assert.Empty(editContext.GetValidationMessages());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static EditContext Validate(object model)
|
||||||
|
{
|
||||||
|
var editContext = new EditContext(model);
|
||||||
|
var validator = new TestObjectGraphDataAnnotationsValidator { EditContext = editContext, };
|
||||||
|
validator.OnInitialized();
|
||||||
|
|
||||||
|
editContext.Validate();
|
||||||
|
|
||||||
|
return editContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static EditContext ValidateField(object model, in FieldIdentifier field)
|
||||||
|
{
|
||||||
|
var editContext = new EditContext(model);
|
||||||
|
var validator = new TestObjectGraphDataAnnotationsValidator { EditContext = editContext, };
|
||||||
|
validator.OnInitialized();
|
||||||
|
|
||||||
|
editContext.NotifyFieldChanged(field);
|
||||||
|
|
||||||
|
return editContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TestObjectGraphDataAnnotationsValidator : ObjectGraphDataAnnotationsValidator
|
||||||
|
{
|
||||||
|
public new void OnInitialized() => base.OnInitialized();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,9 +1,19 @@
|
||||||
@import url('open-iconic/font/css/open-iconic-bootstrap.min.css');
|
@import url('open-iconic/font/css/open-iconic-bootstrap.min.css');
|
||||||
|
|
||||||
html, body {
|
html, body {
|
||||||
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
a, .btn-link {
|
||||||
|
color: #0366d6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary {
|
||||||
|
color: #fff;
|
||||||
|
background-color: #1b6ec2;
|
||||||
|
border-color: #1861ac;
|
||||||
|
}
|
||||||
|
|
||||||
app {
|
app {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
@ -21,8 +31,19 @@ app {
|
||||||
}
|
}
|
||||||
|
|
||||||
.main .top-row {
|
.main .top-row {
|
||||||
background-color: #e6e6e6;
|
background-color: #f7f7f7;
|
||||||
border-bottom: 1px solid #d6d5d5;
|
border-bottom: 1px solid #d6d5d5;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main .top-row > a, .main .top-row .btn-link {
|
||||||
|
white-space: nowrap;
|
||||||
|
margin-left: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main .top-row a:first-child {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar {
|
.sidebar {
|
||||||
|
|
@ -44,20 +65,20 @@ app {
|
||||||
top: -2px;
|
top: -2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-item {
|
.sidebar .nav-item {
|
||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
padding-bottom: 0.5rem;
|
padding-bottom: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-item:first-of-type {
|
.sidebar .nav-item:first-of-type {
|
||||||
padding-top: 1rem;
|
padding-top: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-item:last-of-type {
|
.sidebar .nav-item:last-of-type {
|
||||||
padding-bottom: 1rem;
|
padding-bottom: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-item a {
|
.sidebar .nav-item a {
|
||||||
color: #d7d7d7;
|
color: #d7d7d7;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
height: 3rem;
|
height: 3rem;
|
||||||
|
|
@ -66,12 +87,12 @@ app {
|
||||||
line-height: 3rem;
|
line-height: 3rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-item a.active {
|
.sidebar .nav-item a.active {
|
||||||
background-color: rgba(255,255,255,0.25);
|
background-color: rgba(255,255,255,0.25);
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-item a:hover {
|
.sidebar .nav-item a:hover {
|
||||||
background-color: rgba(255,255,255,0.1);
|
background-color: rgba(255,255,255,0.1);
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
@ -96,9 +117,36 @@ app {
|
||||||
color: red;
|
color: red;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 767.98px) {
|
#blazor-error-ui {
|
||||||
.main .top-row {
|
background: lightyellow;
|
||||||
|
bottom: 0;
|
||||||
|
box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
|
||||||
display: none;
|
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:not(.auth) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main .top-row.auth {
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main .top-row a, .main .top-row .btn-link {
|
||||||
|
margin-left: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -240,6 +240,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ignitor", "Ignitor\src\Igni
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ignitor.Test", "Ignitor\test\Ignitor.Test.csproj", "{F31E8118-014E-4CCE-8A48-5282F7B9BB3E}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ignitor.Test", "Ignitor\test\Ignitor.Test.csproj", "{F31E8118-014E-4CCE-8A48-5282F7B9BB3E}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Validation", "Validation", "{FD9BD646-9D50-42ED-A3E1-90558BA0C6B2}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Blazor.DataAnnotations.Validation", "Blazor\Validation\src\Microsoft.AspNetCore.Blazor.DataAnnotations.Validation.csproj", "{B70F90C7-2696-4050-B24E-BF0308F4E059}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Blazor.DataAnnotations.Validation.Tests", "Blazor\Validation\test\Microsoft.AspNetCore.Blazor.DataAnnotations.Validation.Tests.csproj", "{A5617A9D-C71E-44DE-936C-27611EB40A02}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
|
@ -1486,6 +1492,30 @@ Global
|
||||||
{F31E8118-014E-4CCE-8A48-5282F7B9BB3E}.Release|x64.Build.0 = Release|Any CPU
|
{F31E8118-014E-4CCE-8A48-5282F7B9BB3E}.Release|x64.Build.0 = Release|Any CPU
|
||||||
{F31E8118-014E-4CCE-8A48-5282F7B9BB3E}.Release|x86.ActiveCfg = Release|Any CPU
|
{F31E8118-014E-4CCE-8A48-5282F7B9BB3E}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
{F31E8118-014E-4CCE-8A48-5282F7B9BB3E}.Release|x86.Build.0 = Release|Any CPU
|
{F31E8118-014E-4CCE-8A48-5282F7B9BB3E}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{B70F90C7-2696-4050-B24E-BF0308F4E059}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{B70F90C7-2696-4050-B24E-BF0308F4E059}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{B70F90C7-2696-4050-B24E-BF0308F4E059}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{B70F90C7-2696-4050-B24E-BF0308F4E059}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{B70F90C7-2696-4050-B24E-BF0308F4E059}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{B70F90C7-2696-4050-B24E-BF0308F4E059}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{B70F90C7-2696-4050-B24E-BF0308F4E059}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{B70F90C7-2696-4050-B24E-BF0308F4E059}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{B70F90C7-2696-4050-B24E-BF0308F4E059}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{B70F90C7-2696-4050-B24E-BF0308F4E059}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{B70F90C7-2696-4050-B24E-BF0308F4E059}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{B70F90C7-2696-4050-B24E-BF0308F4E059}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{A5617A9D-C71E-44DE-936C-27611EB40A02}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{A5617A9D-C71E-44DE-936C-27611EB40A02}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{A5617A9D-C71E-44DE-936C-27611EB40A02}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{A5617A9D-C71E-44DE-936C-27611EB40A02}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{A5617A9D-C71E-44DE-936C-27611EB40A02}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{A5617A9D-C71E-44DE-936C-27611EB40A02}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{A5617A9D-C71E-44DE-936C-27611EB40A02}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{A5617A9D-C71E-44DE-936C-27611EB40A02}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{A5617A9D-C71E-44DE-936C-27611EB40A02}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{A5617A9D-C71E-44DE-936C-27611EB40A02}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{A5617A9D-C71E-44DE-936C-27611EB40A02}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{A5617A9D-C71E-44DE-936C-27611EB40A02}.Release|x86.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|
@ -1596,6 +1626,9 @@ Global
|
||||||
{BBF37AF9-8290-4B70-8BA8-0F6017B3B620} = {46E4300C-5726-4108-B9A2-18BB94EB26ED}
|
{BBF37AF9-8290-4B70-8BA8-0F6017B3B620} = {46E4300C-5726-4108-B9A2-18BB94EB26ED}
|
||||||
{CD0EF85C-4187-4515-A355-E5A0D4485F40} = {BDE2397D-C53A-4783-8B3A-1F54F48A6926}
|
{CD0EF85C-4187-4515-A355-E5A0D4485F40} = {BDE2397D-C53A-4783-8B3A-1F54F48A6926}
|
||||||
{F31E8118-014E-4CCE-8A48-5282F7B9BB3E} = {BDE2397D-C53A-4783-8B3A-1F54F48A6926}
|
{F31E8118-014E-4CCE-8A48-5282F7B9BB3E} = {BDE2397D-C53A-4783-8B3A-1F54F48A6926}
|
||||||
|
{FD9BD646-9D50-42ED-A3E1-90558BA0C6B2} = {7260DED9-22A9-4E9D-92F4-5E8A4404DEAF}
|
||||||
|
{B70F90C7-2696-4050-B24E-BF0308F4E059} = {7260DED9-22A9-4E9D-92F4-5E8A4404DEAF}
|
||||||
|
{A5617A9D-C71E-44DE-936C-27611EB40A02} = {7260DED9-22A9-4E9D-92F4-5E8A4404DEAF}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {CC3C47E1-AD1A-4619-9CD3-E08A0148E5CE}
|
SolutionGuid = {CC3C47E1-AD1A-4619-9CD3-E08A0148E5CE}
|
||||||
|
|
|
||||||
|
|
@ -207,7 +207,10 @@ namespace Microsoft.AspNetCore.Components
|
||||||
public sealed partial class EventHandlerAttribute : System.Attribute
|
public sealed partial class EventHandlerAttribute : System.Attribute
|
||||||
{
|
{
|
||||||
public EventHandlerAttribute(string attributeName, System.Type eventArgsType) { }
|
public EventHandlerAttribute(string attributeName, System.Type eventArgsType) { }
|
||||||
|
public EventHandlerAttribute(string attributeName, System.Type eventArgsType, bool enableStopPropagation, bool enablePreventDefault) { }
|
||||||
public string AttributeName { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
|
public string AttributeName { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
|
||||||
|
public bool EnablePreventDefault { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
|
||||||
|
public bool EnableStopPropagation { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
|
||||||
public System.Type EventArgsType { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
|
public System.Type EventArgsType { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
|
||||||
}
|
}
|
||||||
public partial interface IComponent
|
public partial interface IComponent
|
||||||
|
|
|
||||||
|
|
@ -207,7 +207,10 @@ namespace Microsoft.AspNetCore.Components
|
||||||
public sealed partial class EventHandlerAttribute : System.Attribute
|
public sealed partial class EventHandlerAttribute : System.Attribute
|
||||||
{
|
{
|
||||||
public EventHandlerAttribute(string attributeName, System.Type eventArgsType) { }
|
public EventHandlerAttribute(string attributeName, System.Type eventArgsType) { }
|
||||||
|
public EventHandlerAttribute(string attributeName, System.Type eventArgsType, bool enableStopPropagation, bool enablePreventDefault) { }
|
||||||
public string AttributeName { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
|
public string AttributeName { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
|
||||||
|
public bool EnablePreventDefault { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
|
||||||
|
public bool EnableStopPropagation { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
|
||||||
public System.Type EventArgsType { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
|
public System.Type EventArgsType { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
|
||||||
}
|
}
|
||||||
public partial interface IComponent
|
public partial interface IComponent
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,18 @@ namespace Microsoft.AspNetCore.Components
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="attributeName"></param>
|
/// <param name="attributeName"></param>
|
||||||
/// <param name="eventArgsType"></param>
|
/// <param name="eventArgsType"></param>
|
||||||
public EventHandlerAttribute(string attributeName, Type eventArgsType)
|
public EventHandlerAttribute(string attributeName, Type eventArgsType) : this(attributeName, eventArgsType, false, false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constructs an instance of <see cref="EventHandlerAttribute"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="attributeName"></param>
|
||||||
|
/// <param name="eventArgsType"></param>
|
||||||
|
/// <param name="enableStopPropagation"></param>
|
||||||
|
/// <param name="enablePreventDefault"></param>
|
||||||
|
public EventHandlerAttribute(string attributeName, Type eventArgsType, bool enableStopPropagation, bool enablePreventDefault)
|
||||||
{
|
{
|
||||||
if (attributeName == null)
|
if (attributeName == null)
|
||||||
{
|
{
|
||||||
|
|
@ -30,6 +41,8 @@ namespace Microsoft.AspNetCore.Components
|
||||||
|
|
||||||
AttributeName = attributeName;
|
AttributeName = attributeName;
|
||||||
EventArgsType = eventArgsType;
|
EventArgsType = eventArgsType;
|
||||||
|
EnableStopPropagation = enableStopPropagation;
|
||||||
|
EnablePreventDefault = enablePreventDefault;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -41,5 +54,15 @@ namespace Microsoft.AspNetCore.Components
|
||||||
/// Gets the event argument type.
|
/// Gets the event argument type.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Type EventArgsType { get; }
|
public Type EventArgsType { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the event's ability to stop propagation.
|
||||||
|
/// </summary>
|
||||||
|
public bool EnableStopPropagation { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the event's ability to prevent default event flow.
|
||||||
|
/// </summary>
|
||||||
|
public bool EnablePreventDefault { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,8 @@
|
||||||
"Blazor\\Http\\test\\Microsoft.AspNetCore.Blazor.HttpClient.Tests.csproj",
|
"Blazor\\Http\\test\\Microsoft.AspNetCore.Blazor.HttpClient.Tests.csproj",
|
||||||
"Blazor\\Server\\src\\Microsoft.AspNetCore.Blazor.Server.csproj",
|
"Blazor\\Server\\src\\Microsoft.AspNetCore.Blazor.Server.csproj",
|
||||||
"Blazor\\Templates\\src\\Microsoft.AspNetCore.Blazor.Templates.csproj",
|
"Blazor\\Templates\\src\\Microsoft.AspNetCore.Blazor.Templates.csproj",
|
||||||
|
"Blazor\\Validation\\src\\Microsoft.AspNetCore.Blazor.DataAnnotations.Validation.csproj",
|
||||||
|
"Blazor\\Validation\\test\\Microsoft.AspNetCore.Blazor.DataAnnotations.Validation.Tests.csproj",
|
||||||
"Blazor\\testassets\\HostedInAspNet.Client\\HostedInAspNet.Client.csproj",
|
"Blazor\\testassets\\HostedInAspNet.Client\\HostedInAspNet.Client.csproj",
|
||||||
"Blazor\\testassets\\HostedInAspNet.Server\\HostedInAspNet.Server.csproj",
|
"Blazor\\testassets\\HostedInAspNet.Server\\HostedInAspNet.Server.csproj",
|
||||||
"Blazor\\testassets\\Microsoft.AspNetCore.Blazor.E2EPerformance\\Microsoft.AspNetCore.Blazor.E2EPerformance.csproj",
|
"Blazor\\testassets\\Microsoft.AspNetCore.Blazor.E2EPerformance\\Microsoft.AspNetCore.Blazor.E2EPerformance.csproj",
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,12 @@ namespace Microsoft.AspNetCore.Components.Forms
|
||||||
messages.Clear();
|
messages.Clear();
|
||||||
foreach (var validationResult in validationResults)
|
foreach (var validationResult in validationResults)
|
||||||
{
|
{
|
||||||
|
if (!validationResult.MemberNames.Any())
|
||||||
|
{
|
||||||
|
messages.Add(new FieldIdentifier(editContext.Model, fieldName: string.Empty), validationResult.ErrorMessage);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var memberName in validationResult.MemberNames)
|
foreach (var memberName in validationResult.MemberNames)
|
||||||
{
|
{
|
||||||
messages.Add(editContext.Field(memberName), validationResult.ErrorMessage);
|
messages.Add(editContext.Field(memberName), validationResult.ErrorMessage);
|
||||||
|
|
|
||||||
|
|
@ -13,17 +13,21 @@ using Microsoft.AspNetCore.SignalR.Protocol;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Microsoft.Extensions.Logging.Abstractions;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
namespace Ignitor
|
namespace Ignitor
|
||||||
{
|
{
|
||||||
public class BlazorClient : IAsyncDisposable
|
public class BlazorClient : IAsyncDisposable
|
||||||
{
|
{
|
||||||
private const string MarkerPattern = ".*?<!--Blazor:(.*?)-->.*?";
|
private const string MarkerPattern = ".*?<!--Blazor:(.*?)-->.*?";
|
||||||
|
private HubConnection? _hubConnection;
|
||||||
|
|
||||||
public BlazorClient()
|
public BlazorClient()
|
||||||
{
|
{
|
||||||
CancellationTokenSource = new CancellationTokenSource();
|
CancellationTokenSource = new CancellationTokenSource();
|
||||||
TaskCompletionSource = new TaskCompletionSource<object>();
|
CancellationToken = CancellationTokenSource.Token;
|
||||||
|
TaskCompletionSource = new TaskCompletionSource<object?>();
|
||||||
|
|
||||||
CancellationTokenSource.Token.Register(() =>
|
CancellationTokenSource.Token.Register(() =>
|
||||||
{
|
{
|
||||||
|
|
@ -31,7 +35,7 @@ namespace Ignitor
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public TimeSpan? DefaultConnectionTimeout { get; set; } = TimeSpan.FromSeconds(10);
|
public TimeSpan? DefaultConnectionTimeout { get; set; } = TimeSpan.FromSeconds(20);
|
||||||
public TimeSpan? DefaultOperationTimeout { get; set; } = TimeSpan.FromMilliseconds(500);
|
public TimeSpan? DefaultOperationTimeout { get; set; } = TimeSpan.FromMilliseconds(500);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -44,104 +48,103 @@ namespace Ignitor
|
||||||
/// Gets the collections of operation results that are captured when <see cref="CaptureOperations"/>
|
/// Gets the collections of operation results that are captured when <see cref="CaptureOperations"/>
|
||||||
/// is true.
|
/// is true.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Operations Operations { get; private set; }
|
public Operations Operations { get; } = new Operations();
|
||||||
|
|
||||||
public Func<string, Exception> FormatError { get; set; }
|
public Func<string, Exception>? FormatError { get; set; }
|
||||||
|
|
||||||
private CancellationTokenSource CancellationTokenSource { get; }
|
private CancellationTokenSource CancellationTokenSource { get; }
|
||||||
|
|
||||||
private CancellationToken CancellationToken => CancellationTokenSource.Token;
|
private CancellationToken CancellationToken { get; }
|
||||||
|
|
||||||
private TaskCompletionSource<object> TaskCompletionSource { get; }
|
private TaskCompletionSource<object?> TaskCompletionSource { get; }
|
||||||
|
|
||||||
private CancellableOperation<CapturedAttachComponentCall> NextAttachComponentReceived { get; set; }
|
private CancellableOperation<CapturedAttachComponentCall>? NextAttachComponentReceived { get; set; }
|
||||||
|
|
||||||
private CancellableOperation<CapturedRenderBatch> NextBatchReceived { get; set; }
|
private CancellableOperation<CapturedRenderBatch?>? NextBatchReceived { get; set; }
|
||||||
|
|
||||||
private CancellableOperation<string> NextErrorReceived { get; set; }
|
private CancellableOperation<string?>? NextErrorReceived { get; set; }
|
||||||
|
|
||||||
private CancellableOperation<Exception> NextDisconnect { get; set; }
|
private CancellableOperation<Exception?>? NextDisconnect { get; set; }
|
||||||
|
|
||||||
private CancellableOperation<CapturedJSInteropCall> NextJSInteropReceived { get; set; }
|
private CancellableOperation<CapturedJSInteropCall?>? NextJSInteropReceived { get; set; }
|
||||||
|
|
||||||
private CancellableOperation<string> NextDotNetInteropCompletionReceived { get; set; }
|
private CancellableOperation<string?>? NextDotNetInteropCompletionReceived { get; set; }
|
||||||
|
|
||||||
public ILoggerProvider LoggerProvider { get; set; }
|
public ILoggerProvider LoggerProvider { get; set; } = NullLoggerProvider.Instance;
|
||||||
|
|
||||||
public bool ConfirmRenderBatch { get; set; } = true;
|
public bool ConfirmRenderBatch { get; set; } = true;
|
||||||
|
|
||||||
public event Action<CapturedJSInteropCall> JSInterop;
|
public event Action<CapturedJSInteropCall>? JSInterop;
|
||||||
|
|
||||||
public event Action<CapturedRenderBatch> RenderBatchReceived;
|
public event Action<CapturedRenderBatch>? RenderBatchReceived;
|
||||||
|
|
||||||
public event Action<string> DotNetInteropCompletion;
|
public event Action<string>? DotNetInteropCompletion;
|
||||||
|
|
||||||
public event Action<string> OnCircuitError;
|
public event Action<string>? OnCircuitError;
|
||||||
|
|
||||||
public string CircuitId { get; set; }
|
public string? CircuitId { get; private set; }
|
||||||
|
|
||||||
public ElementHive Hive { get; set; } = new ElementHive();
|
public ElementHive Hive { get; } = new ElementHive();
|
||||||
|
|
||||||
public bool ImplicitWait => DefaultOperationTimeout != null;
|
public bool ImplicitWait => DefaultOperationTimeout != null;
|
||||||
|
|
||||||
public HubConnection HubConnection { get; private set; }
|
public HubConnection HubConnection => _hubConnection ?? throw new InvalidOperationException("HubConnection has not been initialized.");
|
||||||
|
|
||||||
public Task<CapturedRenderBatch> PrepareForNextBatch(TimeSpan? timeout)
|
public Task<CapturedRenderBatch?> PrepareForNextBatch(TimeSpan? timeout)
|
||||||
{
|
{
|
||||||
if (NextBatchReceived != null && !NextBatchReceived.Disposed)
|
if (NextBatchReceived != null && !NextBatchReceived.Disposed)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException("Invalid state previous task not completed");
|
throw new InvalidOperationException("Invalid state previous task not completed");
|
||||||
}
|
}
|
||||||
|
|
||||||
NextBatchReceived = new CancellableOperation<CapturedRenderBatch>(timeout);
|
NextBatchReceived = new CancellableOperation<CapturedRenderBatch?>(timeout, CancellationToken);
|
||||||
|
|
||||||
return NextBatchReceived.Completion.Task;
|
return NextBatchReceived.Completion.Task;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<CapturedJSInteropCall> PrepareForNextJSInterop(TimeSpan? timeout)
|
public Task<CapturedJSInteropCall?> PrepareForNextJSInterop(TimeSpan? timeout)
|
||||||
{
|
{
|
||||||
if (NextJSInteropReceived != null && !NextJSInteropReceived.Disposed)
|
if (NextJSInteropReceived != null && !NextJSInteropReceived.Disposed)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException("Invalid state previous task not completed");
|
throw new InvalidOperationException("Invalid state previous task not completed");
|
||||||
}
|
}
|
||||||
|
|
||||||
NextJSInteropReceived = new CancellableOperation<CapturedJSInteropCall>(timeout);
|
NextJSInteropReceived = new CancellableOperation<CapturedJSInteropCall?>(timeout, CancellationToken);
|
||||||
|
|
||||||
return NextJSInteropReceived.Completion.Task;
|
return NextJSInteropReceived.Completion.Task;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<string> PrepareForNextDotNetInterop(TimeSpan? timeout)
|
public Task<string?> PrepareForNextDotNetInterop(TimeSpan? timeout)
|
||||||
{
|
{
|
||||||
if (NextDotNetInteropCompletionReceived != null && !NextDotNetInteropCompletionReceived.Disposed)
|
if (NextDotNetInteropCompletionReceived != null && !NextDotNetInteropCompletionReceived.Disposed)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException("Invalid state previous task not completed");
|
throw new InvalidOperationException("Invalid state previous task not completed");
|
||||||
}
|
}
|
||||||
|
|
||||||
NextDotNetInteropCompletionReceived = new CancellableOperation<string>(timeout);
|
NextDotNetInteropCompletionReceived = new CancellableOperation<string?>(timeout, CancellationToken);
|
||||||
|
|
||||||
return NextDotNetInteropCompletionReceived.Completion.Task;
|
return NextDotNetInteropCompletionReceived.Completion.Task;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<string> PrepareForNextCircuitError(TimeSpan? timeout)
|
public Task<string?> PrepareForNextCircuitError(TimeSpan? timeout)
|
||||||
{
|
{
|
||||||
if (NextErrorReceived != null && !NextErrorReceived.Disposed)
|
if (NextErrorReceived != null && !NextErrorReceived.Disposed)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException("Invalid state previous task not completed");
|
throw new InvalidOperationException("Invalid state previous task not completed");
|
||||||
}
|
}
|
||||||
|
|
||||||
NextErrorReceived = new CancellableOperation<string>(timeout);
|
NextErrorReceived = new CancellableOperation<string?>(timeout, CancellationToken);
|
||||||
|
|
||||||
return NextErrorReceived.Completion.Task;
|
return NextErrorReceived.Completion.Task;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<Exception> PrepareForNextDisconnect(TimeSpan? timeout)
|
public Task<Exception?> PrepareForNextDisconnect(TimeSpan? timeout)
|
||||||
{
|
{
|
||||||
if (NextDisconnect != null && !NextDisconnect.Disposed)
|
if (NextDisconnect != null && !NextDisconnect.Disposed)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException("Invalid state previous task not completed");
|
throw new InvalidOperationException("Invalid state previous task not completed");
|
||||||
}
|
}
|
||||||
|
|
||||||
NextDisconnect = new CancellableOperation<Exception>(timeout);
|
NextDisconnect = new CancellableOperation<Exception?>(timeout, CancellationToken);
|
||||||
|
|
||||||
return NextDisconnect.Completion.Task;
|
return NextDisconnect.Completion.Task;
|
||||||
}
|
}
|
||||||
|
|
@ -172,44 +175,44 @@ namespace Ignitor
|
||||||
return ExpectRenderBatch(() => elementNode.SelectAsync(HubConnection, value));
|
return ExpectRenderBatch(() => elementNode.SelectAsync(HubConnection, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<CapturedRenderBatch> ExpectRenderBatch(Func<Task> action, TimeSpan? timeout = null)
|
public async Task<CapturedRenderBatch?> ExpectRenderBatch(Func<Task> action, TimeSpan? timeout = null)
|
||||||
{
|
{
|
||||||
var task = WaitForRenderBatch(timeout);
|
var task = WaitForRenderBatch(timeout);
|
||||||
await action();
|
await action();
|
||||||
return await task;
|
return await task;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<CapturedJSInteropCall> ExpectJSInterop(Func<Task> action, TimeSpan? timeout = null)
|
public async Task<CapturedJSInteropCall?> ExpectJSInterop(Func<Task> action, TimeSpan? timeout = null)
|
||||||
{
|
{
|
||||||
var task = WaitForJSInterop(timeout);
|
var task = WaitForJSInterop(timeout);
|
||||||
await action();
|
await action();
|
||||||
return await task;
|
return await task;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<string> ExpectDotNetInterop(Func<Task> action, TimeSpan? timeout = null)
|
public async Task<string?> ExpectDotNetInterop(Func<Task> action, TimeSpan? timeout = null)
|
||||||
{
|
{
|
||||||
var task = WaitForDotNetInterop(timeout);
|
var task = WaitForDotNetInterop(timeout);
|
||||||
await action();
|
await action();
|
||||||
return await task;
|
return await task;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<string> ExpectCircuitError(Func<Task> action, TimeSpan? timeout = null)
|
public async Task<string?> ExpectCircuitError(Func<Task> action, TimeSpan? timeout = null)
|
||||||
{
|
{
|
||||||
var task = WaitForCircuitError(timeout);
|
var task = WaitForCircuitError(timeout);
|
||||||
await action();
|
await action();
|
||||||
return await task;
|
return await task;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Exception> ExpectDisconnect(Func<Task> action, TimeSpan? timeout = null)
|
public async Task<Exception?> ExpectDisconnect(Func<Task> action, TimeSpan? timeout = null)
|
||||||
{
|
{
|
||||||
var task = WaitForDisconnect(timeout);
|
var task = WaitForDisconnect(timeout);
|
||||||
await action();
|
await action();
|
||||||
return await task;
|
return await task;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<(string error, Exception exception)> ExpectCircuitErrorAndDisconnect(Func<Task> action, TimeSpan? timeout = null)
|
public async Task<(string? error, Exception? exception)> ExpectCircuitErrorAndDisconnect(Func<Task> action, TimeSpan? timeout = null)
|
||||||
{
|
{
|
||||||
string error = null;
|
string? error = default;
|
||||||
|
|
||||||
// NOTE: timeout is used for each operation individually.
|
// NOTE: timeout is used for each operation individually.
|
||||||
var exception = await ExpectDisconnect(async () =>
|
var exception = await ExpectDisconnect(async () =>
|
||||||
|
|
@ -220,7 +223,7 @@ namespace Ignitor
|
||||||
return (error, exception);
|
return (error, exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<CapturedRenderBatch> WaitForRenderBatch(TimeSpan? timeout = null)
|
private async Task<CapturedRenderBatch?> WaitForRenderBatch(TimeSpan? timeout = null)
|
||||||
{
|
{
|
||||||
if (ImplicitWait)
|
if (ImplicitWait)
|
||||||
{
|
{
|
||||||
|
|
@ -233,7 +236,7 @@ namespace Ignitor
|
||||||
{
|
{
|
||||||
return await PrepareForNextBatch(timeout ?? DefaultOperationTimeout);
|
return await PrepareForNextBatch(timeout ?? DefaultOperationTimeout);
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException)
|
catch (TimeoutException) when (FormatError != null)
|
||||||
{
|
{
|
||||||
throw FormatError("Timed out while waiting for batch.");
|
throw FormatError("Timed out while waiting for batch.");
|
||||||
}
|
}
|
||||||
|
|
@ -242,7 +245,7 @@ namespace Ignitor
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<CapturedJSInteropCall> WaitForJSInterop(TimeSpan? timeout = null)
|
private async Task<CapturedJSInteropCall?> WaitForJSInterop(TimeSpan? timeout = null)
|
||||||
{
|
{
|
||||||
if (ImplicitWait)
|
if (ImplicitWait)
|
||||||
{
|
{
|
||||||
|
|
@ -255,7 +258,7 @@ namespace Ignitor
|
||||||
{
|
{
|
||||||
return await PrepareForNextJSInterop(timeout ?? DefaultOperationTimeout);
|
return await PrepareForNextJSInterop(timeout ?? DefaultOperationTimeout);
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException)
|
catch (TimeoutException) when (FormatError != null)
|
||||||
{
|
{
|
||||||
throw FormatError("Timed out while waiting for JS Interop.");
|
throw FormatError("Timed out while waiting for JS Interop.");
|
||||||
}
|
}
|
||||||
|
|
@ -264,7 +267,7 @@ namespace Ignitor
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<string> WaitForDotNetInterop(TimeSpan? timeout = null)
|
private async Task<string?> WaitForDotNetInterop(TimeSpan? timeout = null)
|
||||||
{
|
{
|
||||||
if (ImplicitWait)
|
if (ImplicitWait)
|
||||||
{
|
{
|
||||||
|
|
@ -277,7 +280,7 @@ namespace Ignitor
|
||||||
{
|
{
|
||||||
return await PrepareForNextDotNetInterop(timeout ?? DefaultOperationTimeout);
|
return await PrepareForNextDotNetInterop(timeout ?? DefaultOperationTimeout);
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException)
|
catch (TimeoutException) when (FormatError != null)
|
||||||
{
|
{
|
||||||
throw FormatError("Timed out while waiting for .NET interop.");
|
throw FormatError("Timed out while waiting for .NET interop.");
|
||||||
}
|
}
|
||||||
|
|
@ -286,7 +289,7 @@ namespace Ignitor
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<string> WaitForCircuitError(TimeSpan? timeout = null)
|
private async Task<string?> WaitForCircuitError(TimeSpan? timeout = null)
|
||||||
{
|
{
|
||||||
if (ImplicitWait)
|
if (ImplicitWait)
|
||||||
{
|
{
|
||||||
|
|
@ -299,7 +302,7 @@ namespace Ignitor
|
||||||
{
|
{
|
||||||
return await PrepareForNextCircuitError(timeout ?? DefaultOperationTimeout);
|
return await PrepareForNextCircuitError(timeout ?? DefaultOperationTimeout);
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException)
|
catch (TimeoutException) when (FormatError != null)
|
||||||
{
|
{
|
||||||
throw FormatError("Timed out while waiting for circuit error.");
|
throw FormatError("Timed out while waiting for circuit error.");
|
||||||
}
|
}
|
||||||
|
|
@ -308,7 +311,7 @@ namespace Ignitor
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<Exception> WaitForDisconnect(TimeSpan? timeout = null)
|
private async Task<Exception?> WaitForDisconnect(TimeSpan? timeout = null)
|
||||||
{
|
{
|
||||||
if (ImplicitWait)
|
if (ImplicitWait)
|
||||||
{
|
{
|
||||||
|
|
@ -321,7 +324,7 @@ namespace Ignitor
|
||||||
{
|
{
|
||||||
return await PrepareForNextDisconnect(timeout ?? DefaultOperationTimeout);
|
return await PrepareForNextDisconnect(timeout ?? DefaultOperationTimeout);
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException)
|
catch (TimeoutException) when (FormatError != null)
|
||||||
{
|
{
|
||||||
throw FormatError("Timed out while waiting for disconnect.");
|
throw FormatError("Timed out while waiting for disconnect.");
|
||||||
}
|
}
|
||||||
|
|
@ -344,7 +347,7 @@ namespace Ignitor
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
HubConnection = builder.Build();
|
_hubConnection = builder.Build();
|
||||||
await HubConnection.StartAsync(CancellationToken);
|
await HubConnection.StartAsync(CancellationToken);
|
||||||
|
|
||||||
HubConnection.On<int, string>("JS.AttachComponent", OnAttachComponent);
|
HubConnection.On<int, string>("JS.AttachComponent", OnAttachComponent);
|
||||||
|
|
@ -354,11 +357,6 @@ namespace Ignitor
|
||||||
HubConnection.On<string>("JS.Error", OnError);
|
HubConnection.On<string>("JS.Error", OnError);
|
||||||
HubConnection.Closed += OnClosedAsync;
|
HubConnection.Closed += OnClosedAsync;
|
||||||
|
|
||||||
if (CaptureOperations)
|
|
||||||
{
|
|
||||||
Operations = new Operations();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!connectAutomatically)
|
if (!connectAutomatically)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -366,7 +364,7 @@ namespace Ignitor
|
||||||
|
|
||||||
var descriptors = await GetPrerenderDescriptors(uri);
|
var descriptors = await GetPrerenderDescriptors(uri);
|
||||||
await ExpectRenderBatch(
|
await ExpectRenderBatch(
|
||||||
async () => CircuitId = await HubConnection.InvokeAsync<string>("StartCircuit", uri, uri, descriptors),
|
async () => CircuitId = await HubConnection.InvokeAsync<string>("StartCircuit", uri, uri, descriptors, CancellationToken),
|
||||||
DefaultConnectionTimeout);
|
DefaultConnectionTimeout);
|
||||||
return CircuitId != null;
|
return CircuitId != null;
|
||||||
}
|
}
|
||||||
|
|
@ -415,9 +413,9 @@ namespace Ignitor
|
||||||
NextBatchReceived?.Completion?.TrySetResult(null);
|
NextBatchReceived?.Completion?.TrySetResult(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task ConfirmBatch(int batchId, string error = null)
|
public Task ConfirmBatch(int batchId, string? error = null)
|
||||||
{
|
{
|
||||||
return HubConnection.InvokeAsync("OnRenderCompleted", batchId, error);
|
return HubConnection.InvokeAsync("OnRenderCompleted", batchId, error, CancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnError(string error)
|
private void OnError(string error)
|
||||||
|
|
@ -468,7 +466,14 @@ namespace Ignitor
|
||||||
|
|
||||||
public async Task InvokeDotNetMethod(object callId, string assemblyName, string methodIdentifier, object dotNetObjectId, string argsJson)
|
public async Task InvokeDotNetMethod(object callId, string assemblyName, string methodIdentifier, object dotNetObjectId, string argsJson)
|
||||||
{
|
{
|
||||||
await ExpectDotNetInterop(() => HubConnection.InvokeAsync("BeginInvokeDotNetFromJS", callId?.ToString(), assemblyName, methodIdentifier, dotNetObjectId ?? 0, argsJson));
|
await ExpectDotNetInterop(() => HubConnection.InvokeAsync(
|
||||||
|
"BeginInvokeDotNetFromJS",
|
||||||
|
callId?.ToString(),
|
||||||
|
assemblyName,
|
||||||
|
methodIdentifier,
|
||||||
|
dotNetObjectId ?? 0,
|
||||||
|
argsJson,
|
||||||
|
CancellationToken));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<string> GetPrerenderDescriptors(Uri uri)
|
public async Task<string> GetPrerenderDescriptors(Uri uri)
|
||||||
|
|
@ -484,10 +489,13 @@ namespace Ignitor
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Cancel()
|
public void Cancel()
|
||||||
|
{
|
||||||
|
if (!CancellationTokenSource.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
CancellationTokenSource.Cancel();
|
CancellationTokenSource.Cancel();
|
||||||
CancellationTokenSource.Dispose();
|
CancellationTokenSource.Dispose();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public ElementNode FindElementById(string id)
|
public ElementNode FindElementById(string id)
|
||||||
{
|
{
|
||||||
|
|
@ -519,6 +527,7 @@ namespace Ignitor
|
||||||
|
|
||||||
public async ValueTask DisposeAsync()
|
public async ValueTask DisposeAsync()
|
||||||
{
|
{
|
||||||
|
Cancel();
|
||||||
if (HubConnection != null)
|
if (HubConnection != null)
|
||||||
{
|
{
|
||||||
await HubConnection.DisposeAsync();
|
await HubConnection.DisposeAsync();
|
||||||
|
|
@ -526,3 +535,5 @@ namespace Ignitor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#nullable restore
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,12 @@ using System;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
namespace Ignitor
|
namespace Ignitor
|
||||||
{
|
{
|
||||||
internal class CancellableOperation<TResult>
|
internal class CancellableOperation<TResult>
|
||||||
{
|
{
|
||||||
public CancellableOperation(TimeSpan? timeout)
|
public CancellableOperation(TimeSpan? timeout, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
Timeout = timeout;
|
Timeout = timeout;
|
||||||
|
|
||||||
|
|
@ -17,26 +18,38 @@ namespace Ignitor
|
||||||
Completion.Task.ContinueWith(
|
Completion.Task.ContinueWith(
|
||||||
(task, state) =>
|
(task, state) =>
|
||||||
{
|
{
|
||||||
var operation = (CancellableOperation<TResult>)state;
|
var operation = (CancellableOperation<TResult>)state!;
|
||||||
operation.Dispose();
|
operation.Dispose();
|
||||||
},
|
},
|
||||||
this,
|
this,
|
||||||
TaskContinuationOptions.ExecuteSynchronously); // We need to execute synchronously to clean-up before anything else continues
|
TaskContinuationOptions.ExecuteSynchronously); // We need to execute synchronously to clean-up before anything else continues
|
||||||
|
|
||||||
|
|
||||||
|
Cancellation = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
|
||||||
|
|
||||||
if (Timeout != null && Timeout != System.Threading.Timeout.InfiniteTimeSpan && Timeout != TimeSpan.MaxValue)
|
if (Timeout != null && Timeout != System.Threading.Timeout.InfiniteTimeSpan && Timeout != TimeSpan.MaxValue)
|
||||||
{
|
{
|
||||||
Cancellation = new CancellationTokenSource(Timeout.Value);
|
Cancellation.CancelAfter(Timeout.Value);
|
||||||
|
}
|
||||||
|
|
||||||
CancellationRegistration = Cancellation.Token.Register(
|
CancellationRegistration = Cancellation.Token.Register(
|
||||||
(self) =>
|
(self) =>
|
||||||
{
|
{
|
||||||
var operation = (CancellableOperation<TResult>)self;
|
var operation = (CancellableOperation<TResult>)self!;
|
||||||
operation.Completion.TrySetCanceled(operation.Cancellation.Token);
|
|
||||||
operation.Cancellation.Dispose();
|
if (cancellationToken.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
// The operation was externally canceled before it timed out.
|
||||||
|
Dispose();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
operation.Completion.TrySetException(new TimeoutException($"The operation timed out after {Timeout}."));
|
||||||
|
operation.Cancellation?.Dispose();
|
||||||
operation.CancellationRegistration.Dispose();
|
operation.CancellationRegistration.Dispose();
|
||||||
},
|
},
|
||||||
this);
|
this);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public TimeSpan? Timeout { get; }
|
public TimeSpan? Timeout { get; }
|
||||||
|
|
||||||
|
|
@ -62,3 +75,4 @@ namespace Ignitor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#nullable restore
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
namespace Ignitor
|
namespace Ignitor
|
||||||
{
|
{
|
||||||
|
#nullable enable
|
||||||
public class ComponentState
|
public class ComponentState
|
||||||
{
|
{
|
||||||
public ComponentState(int componentId)
|
public ComponentState(int componentId)
|
||||||
|
|
@ -11,6 +12,7 @@ namespace Ignitor
|
||||||
}
|
}
|
||||||
|
|
||||||
public int ComponentId { get; }
|
public int ComponentId { get; }
|
||||||
public IComponent Component { get; }
|
public IComponent? Component { get; }
|
||||||
}
|
}
|
||||||
|
#nullable restore
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
namespace Ignitor
|
namespace Ignitor
|
||||||
{
|
{
|
||||||
public abstract class ContainerNode : Node
|
public abstract class ContainerNode : Node
|
||||||
|
|
@ -82,3 +83,4 @@ namespace Ignitor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#nullable restore
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,9 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
namespace Ignitor
|
namespace Ignitor
|
||||||
{
|
{
|
||||||
public class ElementHive
|
public class ElementHive
|
||||||
|
|
@ -35,7 +37,7 @@ namespace Ignitor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryFindElementById(string id, out ElementNode element)
|
public bool TryFindElementById(string id, [NotNullWhen(true)] out ElementNode? element)
|
||||||
{
|
{
|
||||||
foreach (var kvp in Components)
|
foreach (var kvp in Components)
|
||||||
{
|
{
|
||||||
|
|
@ -49,7 +51,7 @@ namespace Ignitor
|
||||||
element = null;
|
element = null;
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
bool TryGetElementFromChildren(Node node, out ElementNode foundNode)
|
bool TryGetElementFromChildren(Node node, out ElementNode? foundNode)
|
||||||
{
|
{
|
||||||
if (node is ElementNode elementNode &&
|
if (node is ElementNode elementNode &&
|
||||||
elementNode.Attributes.TryGetValue("id", out var elementId) &&
|
elementNode.Attributes.TryGetValue("id", out var elementId) &&
|
||||||
|
|
@ -81,6 +83,7 @@ namespace Ignitor
|
||||||
{
|
{
|
||||||
component = new ComponentNode(componentId);
|
component = new ComponentNode(componentId);
|
||||||
Components.Add(componentId, component);
|
Components.Add(componentId, component);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ApplyEdits(batch, component, 0, edits);
|
ApplyEdits(batch, component, 0, edits);
|
||||||
|
|
@ -199,7 +202,7 @@ namespace Ignitor
|
||||||
|
|
||||||
case RenderTreeEditType.StepOut:
|
case RenderTreeEditType.StepOut:
|
||||||
{
|
{
|
||||||
parent = parent.Parent;
|
parent = parent.Parent ?? throw new InvalidOperationException($"Cannot step out of {parent}");
|
||||||
currentDepth--;
|
currentDepth--;
|
||||||
childIndexAtCurrentDepth = currentDepth == 0 ? childIndex : 0; // The childIndex is only ever nonzero at zero depth
|
childIndexAtCurrentDepth = currentDepth == 0 ? childIndex : 0; // The childIndex is only ever nonzero at zero depth
|
||||||
break;
|
break;
|
||||||
|
|
@ -469,3 +472,4 @@ namespace Ignitor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#nullable restore
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ using System.Text.Json;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.SignalR.Client;
|
using Microsoft.AspNetCore.SignalR.Client;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
namespace Ignitor
|
namespace Ignitor
|
||||||
{
|
{
|
||||||
public class ElementNode : ContainerNode
|
public class ElementNode : ContainerNode
|
||||||
|
|
@ -87,7 +88,7 @@ namespace Ignitor
|
||||||
return DispatchEventCore(connection, Serialize(webEventDescriptor), Serialize(args));
|
return DispatchEventCore(connection, Serialize(webEventDescriptor), Serialize(args));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task ClickAsync(HubConnection connection)
|
internal Task ClickAsync(HubConnection connection)
|
||||||
{
|
{
|
||||||
if (!Events.TryGetValue("click", out var clickEventDescriptor))
|
if (!Events.TryGetValue("click", out var clickEventDescriptor))
|
||||||
{
|
{
|
||||||
|
|
@ -129,3 +130,4 @@ namespace Ignitor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#nullable restore
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// 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.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
namespace Ignitor
|
namespace Ignitor
|
||||||
{
|
{
|
||||||
public class Error
|
public class Error
|
||||||
{
|
{
|
||||||
public string Stack { get; set; }
|
public string? Stack { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#nullable restore
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
using System;
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
using System.Collections.Generic;
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace Ignitor
|
namespace Ignitor
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,14 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// 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.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
namespace Ignitor
|
namespace Ignitor
|
||||||
{
|
{
|
||||||
public abstract class Node
|
public abstract class Node
|
||||||
{
|
{
|
||||||
public virtual ContainerNode Parent { get; set; }
|
public virtual ContainerNode? Parent { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#nullable restore
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
namespace Ignitor
|
namespace Ignitor
|
||||||
{
|
{
|
||||||
internal static class NodeSerializer
|
internal static class NodeSerializer
|
||||||
|
|
@ -96,7 +98,7 @@ namespace Ignitor
|
||||||
if (attribute.Value != null)
|
if (attribute.Value != null)
|
||||||
{
|
{
|
||||||
Write("=\"");
|
Write("=\"");
|
||||||
Write(attribute.Value.ToString());
|
Write(attribute.Value.ToString()!);
|
||||||
Write("\"");
|
Write("\"");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -113,7 +115,7 @@ namespace Ignitor
|
||||||
if (properties.Value != null)
|
if (properties.Value != null)
|
||||||
{
|
{
|
||||||
Write("=\"");
|
Write("=\"");
|
||||||
Write(properties.Value.ToString());
|
Write(properties.Value.ToString()!);
|
||||||
Write("\"");
|
Write("\"");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -194,3 +196,4 @@ namespace Ignitor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#nullable restore
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
namespace Ignitor
|
namespace Ignitor
|
||||||
{
|
{
|
||||||
public sealed class Operations
|
public sealed class Operations
|
||||||
|
|
@ -18,3 +19,4 @@ namespace Ignitor
|
||||||
public ConcurrentQueue<CapturedJSInteropCall> JSInteropCalls { get; } = new ConcurrentQueue<CapturedJSInteropCall>();
|
public ConcurrentQueue<CapturedJSInteropCall> JSInteropCalls { get; } = new ConcurrentQueue<CapturedJSInteropCall>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#nullable restore
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
namespace Ignitor
|
namespace Ignitor
|
||||||
{
|
{
|
||||||
public static class RenderBatchReader
|
public static class RenderBatchReader
|
||||||
|
|
@ -206,7 +208,7 @@ namespace Ignitor
|
||||||
return new ArrayRange<ulong>(Array.Empty<ulong>(), 0);
|
return new ArrayRange<ulong>(Array.Empty<ulong>(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string ReadString(ReadOnlySpan<byte> data, string[] strings)
|
private static string? ReadString(ReadOnlySpan<byte> data, string[] strings)
|
||||||
{
|
{
|
||||||
var index = BitConverter.ToInt32(data.Slice(0, 4));
|
var index = BitConverter.ToInt32(data.Slice(0, 4));
|
||||||
return index >= 0 ? strings[index] : null;
|
return index >= 0 ? strings[index] : null;
|
||||||
|
|
@ -279,3 +281,4 @@ namespace Ignitor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#nullable restore
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@
|
||||||
<Reference Include="Microsoft.AspNetCore.HttpsPolicy" />
|
<Reference Include="Microsoft.AspNetCore.HttpsPolicy" />
|
||||||
<Reference Include="Microsoft.AspNetCore.Mvc" />
|
<Reference Include="Microsoft.AspNetCore.Mvc" />
|
||||||
<Reference Include="Microsoft.Extensions.Hosting" />
|
<Reference Include="Microsoft.Extensions.Hosting" />
|
||||||
|
<Reference Include="Microsoft.AspNetCore.Blazor.DataAnnotations.Validation" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
||||||
|
|
@ -36,10 +36,16 @@ app {
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
}
|
}
|
||||||
|
|
||||||
.main .top-row > a {
|
.main .top-row > a, .main .top-row .btn-link {
|
||||||
|
white-space: nowrap;
|
||||||
margin-left: 1.5rem;
|
margin-left: 1.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.main .top-row a:first-child {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
.sidebar {
|
.sidebar {
|
||||||
background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%);
|
background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%);
|
||||||
}
|
}
|
||||||
|
|
@ -59,20 +65,20 @@ app {
|
||||||
top: -2px;
|
top: -2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-item {
|
.sidebar .nav-item {
|
||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
padding-bottom: 0.5rem;
|
padding-bottom: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-item:first-of-type {
|
.sidebar .nav-item:first-of-type {
|
||||||
padding-top: 1rem;
|
padding-top: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-item:last-of-type {
|
.sidebar .nav-item:last-of-type {
|
||||||
padding-bottom: 1rem;
|
padding-bottom: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-item a {
|
.sidebar .nav-item a {
|
||||||
color: #d7d7d7;
|
color: #d7d7d7;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
height: 3rem;
|
height: 3rem;
|
||||||
|
|
@ -81,12 +87,12 @@ app {
|
||||||
line-height: 3rem;
|
line-height: 3rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-item a.active {
|
.sidebar .nav-item a.active {
|
||||||
background-color: rgba(255,255,255,0.25);
|
background-color: rgba(255,255,255,0.25);
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-item a:hover {
|
.sidebar .nav-item a:hover {
|
||||||
background-color: rgba(255,255,255,0.1);
|
background-color: rgba(255,255,255,0.1);
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
@ -131,9 +137,17 @@ app {
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 767.98px) {
|
@media (max-width: 767.98px) {
|
||||||
.main .top-row {
|
.main .top-row:not(.auth) {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.main .top-row.auth {
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main .top-row a, .main .top-row .btn-link {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width: 768px) {
|
@media (min-width: 768px) {
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ using MessagePack;
|
||||||
using Microsoft.AspNetCore.Connections;
|
using Microsoft.AspNetCore.Connections;
|
||||||
using Microsoft.AspNetCore.Internal;
|
using Microsoft.AspNetCore.Internal;
|
||||||
using Microsoft.AspNetCore.SignalR;
|
using Microsoft.AspNetCore.SignalR;
|
||||||
|
using Microsoft.AspNetCore.SignalR.Internal;
|
||||||
using Microsoft.AspNetCore.SignalR.Protocol;
|
using Microsoft.AspNetCore.SignalR.Protocol;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Components.Server.BlazorPack
|
namespace Microsoft.AspNetCore.Components.Server.BlazorPack
|
||||||
|
|
@ -19,6 +20,7 @@ namespace Microsoft.AspNetCore.Components.Server.BlazorPack
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Implements the SignalR Hub Protocol using MessagePack with limited type support.
|
/// Implements the SignalR Hub Protocol using MessagePack with limited type support.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[NonDefaultHubProtocol]
|
||||||
internal sealed class BlazorPackHubProtocol : IHubProtocol
|
internal sealed class BlazorPackHubProtocol : IHubProtocol
|
||||||
{
|
{
|
||||||
internal const string ProtocolName = "blazorpack";
|
internal const string ProtocolName = "blazorpack";
|
||||||
|
|
@ -78,7 +80,7 @@ namespace Microsoft.AspNetCore.Components.Server.BlazorPack
|
||||||
message = PingMessage.Instance;
|
message = PingMessage.Instance;
|
||||||
return true;
|
return true;
|
||||||
case HubProtocolConstants.CloseMessageType:
|
case HubProtocolConstants.CloseMessageType:
|
||||||
message = CreateCloseMessage(ref reader);
|
message = CreateCloseMessage(ref reader, itemCount);
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
// Future protocol changes can add message types, old clients can ignore them
|
// Future protocol changes can add message types, old clients can ignore them
|
||||||
|
|
@ -196,10 +198,23 @@ namespace Microsoft.AspNetCore.Components.Server.BlazorPack
|
||||||
return ApplyHeaders(headers, new CancelInvocationMessage(invocationId));
|
return ApplyHeaders(headers, new CancelInvocationMessage(invocationId));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static CloseMessage CreateCloseMessage(ref MessagePackReader reader)
|
private static CloseMessage CreateCloseMessage(ref MessagePackReader reader, int itemCount)
|
||||||
{
|
{
|
||||||
var error = ReadString(ref reader, "error");
|
var error = ReadString(ref reader, "error");
|
||||||
return new CloseMessage(error);
|
var allowReconnect = false;
|
||||||
|
|
||||||
|
if (itemCount > 2)
|
||||||
|
{
|
||||||
|
allowReconnect = ReadBoolean(ref reader, "allowReconnect");
|
||||||
|
}
|
||||||
|
|
||||||
|
// An empty string is still an error
|
||||||
|
if (error == null && !allowReconnect)
|
||||||
|
{
|
||||||
|
return CloseMessage.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new CloseMessage(error, allowReconnect);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Dictionary<string, string> ReadHeaders(ref MessagePackReader reader)
|
private static Dictionary<string, string> ReadHeaders(ref MessagePackReader reader)
|
||||||
|
|
@ -515,7 +530,7 @@ namespace Microsoft.AspNetCore.Components.Server.BlazorPack
|
||||||
|
|
||||||
private void WriteCloseMessage(CloseMessage message, ref MessagePackWriter writer)
|
private void WriteCloseMessage(CloseMessage message, ref MessagePackWriter writer)
|
||||||
{
|
{
|
||||||
writer.WriteArrayHeader(2);
|
writer.WriteArrayHeader(3);
|
||||||
writer.Write(HubProtocolConstants.CloseMessageType);
|
writer.Write(HubProtocolConstants.CloseMessageType);
|
||||||
if (string.IsNullOrEmpty(message.Error))
|
if (string.IsNullOrEmpty(message.Error))
|
||||||
{
|
{
|
||||||
|
|
@ -525,6 +540,8 @@ namespace Microsoft.AspNetCore.Components.Server.BlazorPack
|
||||||
{
|
{
|
||||||
writer.Write(message.Error);
|
writer.Write(message.Error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
writer.Write(message.AllowReconnect);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void WritePingMessage(PingMessage _, ref MessagePackWriter writer)
|
private void WritePingMessage(PingMessage _, ref MessagePackWriter writer)
|
||||||
|
|
@ -559,6 +576,17 @@ namespace Microsoft.AspNetCore.Components.Server.BlazorPack
|
||||||
return destination;
|
return destination;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static bool ReadBoolean(ref MessagePackReader reader, string field)
|
||||||
|
{
|
||||||
|
if (reader.End || reader.NextMessagePackType != MessagePackType.Boolean)
|
||||||
|
{
|
||||||
|
ThrowInvalidDataException(field, "Boolean");
|
||||||
|
}
|
||||||
|
|
||||||
|
return reader.ReadBoolean();
|
||||||
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private static int ReadInt32(ref MessagePackReader reader, string field)
|
private static int ReadInt32(ref MessagePackReader reader, string field)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.SignalR.Internal
|
||||||
|
{
|
||||||
|
// Tells SignalR not to add the IHubProtocol with this attribute to all hubs by default
|
||||||
|
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
|
||||||
|
internal class NonDefaultHubProtocolAttribute : Attribute
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -545,7 +545,7 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return $"There was an unhandled exception on the current circuit, so this circuit will be terminated. For more details turn on " +
|
return $"There was an unhandled exception on the current circuit, so this circuit will be terminated. For more details turn on " +
|
||||||
$"detailed exceptions in '{typeof(CircuitOptions).Name}.{nameof(CircuitOptions.DetailedErrors)}'. {additionalInformation}";
|
$"detailed exceptions by setting 'DetailedErrors: true' in 'appSettings.Development.json' or set '{typeof(CircuitOptions).Name}.{nameof(CircuitOptions.DetailedErrors)}'. {additionalInformation}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -26,7 +26,7 @@ export function attachDebuggerHotkey(loadAssemblyUrls: string[]) {
|
||||||
if (!hasReferencedPdbs) {
|
if (!hasReferencedPdbs) {
|
||||||
console.error('Cannot start debugging, because the application was not compiled with debugging enabled.');
|
console.error('Cannot start debugging, because the application was not compiled with debugging enabled.');
|
||||||
} else if (!currentBrowserIsChrome) {
|
} else if (!currentBrowserIsChrome) {
|
||||||
console.error('Currently, only Chrome is supported for debugging.');
|
console.error('Currently, only Edge(Chromium) or Chrome is supported for debugging.');
|
||||||
} else {
|
} else {
|
||||||
launchDebugger();
|
launchDebugger();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -125,6 +125,8 @@ namespace Microsoft.AspNetCore.Components.Forms
|
||||||
public ValidationSummary() { }
|
public ValidationSummary() { }
|
||||||
[Microsoft.AspNetCore.Components.ParameterAttribute(CaptureUnmatchedValues=true)]
|
[Microsoft.AspNetCore.Components.ParameterAttribute(CaptureUnmatchedValues=true)]
|
||||||
public System.Collections.Generic.IReadOnlyDictionary<string, object> AdditionalAttributes { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
public System.Collections.Generic.IReadOnlyDictionary<string, object> AdditionalAttributes { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||||
|
[Microsoft.AspNetCore.Components.ParameterAttribute]
|
||||||
|
public object Model { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||||
protected override void BuildRenderTree(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder builder) { }
|
protected override void BuildRenderTree(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder builder) { }
|
||||||
protected virtual void Dispose(bool disposing) { }
|
protected virtual void Dispose(bool disposing) { }
|
||||||
protected override void OnParametersSet() { }
|
protected override void OnParametersSet() { }
|
||||||
|
|
@ -222,97 +224,97 @@ namespace Microsoft.AspNetCore.Components.Web
|
||||||
public string Message { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
public string Message { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||||
public string Type { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
public string Type { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||||
}
|
}
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onabort", typeof(Microsoft.AspNetCore.Components.Web.ProgressEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onabort", typeof(Microsoft.AspNetCore.Components.Web.ProgressEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onactivate", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onactivate", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onbeforeactivate", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onbeforeactivate", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onbeforecopy", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onbeforecopy", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onbeforecut", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onbeforecut", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onbeforedeactivate", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onbeforedeactivate", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onbeforepaste", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onbeforepaste", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onblur", typeof(Microsoft.AspNetCore.Components.Web.FocusEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onblur", typeof(Microsoft.AspNetCore.Components.Web.FocusEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("oncanplay", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("oncanplay", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("oncanplaythrough", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("oncanplaythrough", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onchange", typeof(Microsoft.AspNetCore.Components.ChangeEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onchange", typeof(Microsoft.AspNetCore.Components.ChangeEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onclick", typeof(Microsoft.AspNetCore.Components.Web.MouseEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onclick", typeof(Microsoft.AspNetCore.Components.Web.MouseEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("oncontextmenu", typeof(Microsoft.AspNetCore.Components.Web.MouseEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("oncontextmenu", typeof(Microsoft.AspNetCore.Components.Web.MouseEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("oncopy", typeof(Microsoft.AspNetCore.Components.Web.ClipboardEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("oncopy", typeof(Microsoft.AspNetCore.Components.Web.ClipboardEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("oncuechange", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("oncuechange", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("oncut", typeof(Microsoft.AspNetCore.Components.Web.ClipboardEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("oncut", typeof(Microsoft.AspNetCore.Components.Web.ClipboardEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondblclick", typeof(Microsoft.AspNetCore.Components.Web.MouseEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondblclick", typeof(Microsoft.AspNetCore.Components.Web.MouseEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondeactivate", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondeactivate", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondrag", typeof(Microsoft.AspNetCore.Components.Web.DragEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondrag", typeof(Microsoft.AspNetCore.Components.Web.DragEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondragend", typeof(Microsoft.AspNetCore.Components.Web.DragEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondragend", typeof(Microsoft.AspNetCore.Components.Web.DragEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondragenter", typeof(Microsoft.AspNetCore.Components.Web.DragEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondragenter", typeof(Microsoft.AspNetCore.Components.Web.DragEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondragleave", typeof(Microsoft.AspNetCore.Components.Web.DragEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondragleave", typeof(Microsoft.AspNetCore.Components.Web.DragEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondragover", typeof(Microsoft.AspNetCore.Components.Web.DragEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondragover", typeof(Microsoft.AspNetCore.Components.Web.DragEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondragstart", typeof(Microsoft.AspNetCore.Components.Web.DragEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondragstart", typeof(Microsoft.AspNetCore.Components.Web.DragEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondrop", typeof(Microsoft.AspNetCore.Components.Web.DragEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondrop", typeof(Microsoft.AspNetCore.Components.Web.DragEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondurationchange", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondurationchange", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onemptied", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onemptied", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onended", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onended", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onerror", typeof(Microsoft.AspNetCore.Components.Web.ErrorEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onerror", typeof(Microsoft.AspNetCore.Components.Web.ErrorEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onfocus", typeof(Microsoft.AspNetCore.Components.Web.FocusEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onfocus", typeof(Microsoft.AspNetCore.Components.Web.FocusEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onfocusin", typeof(Microsoft.AspNetCore.Components.Web.FocusEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onfocusin", typeof(Microsoft.AspNetCore.Components.Web.FocusEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onfocusout", typeof(Microsoft.AspNetCore.Components.Web.FocusEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onfocusout", typeof(Microsoft.AspNetCore.Components.Web.FocusEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onfullscreenchange", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onfullscreenchange", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onfullscreenerror", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onfullscreenerror", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ongotpointercapture", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ongotpointercapture", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("oninput", typeof(Microsoft.AspNetCore.Components.ChangeEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("oninput", typeof(Microsoft.AspNetCore.Components.ChangeEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("oninvalid", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("oninvalid", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onkeydown", typeof(Microsoft.AspNetCore.Components.Web.KeyboardEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onkeydown", typeof(Microsoft.AspNetCore.Components.Web.KeyboardEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onkeypress", typeof(Microsoft.AspNetCore.Components.Web.KeyboardEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onkeypress", typeof(Microsoft.AspNetCore.Components.Web.KeyboardEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onkeyup", typeof(Microsoft.AspNetCore.Components.Web.KeyboardEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onkeyup", typeof(Microsoft.AspNetCore.Components.Web.KeyboardEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onload", typeof(Microsoft.AspNetCore.Components.Web.ProgressEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onload", typeof(Microsoft.AspNetCore.Components.Web.ProgressEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onloadeddata", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onloadeddata", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onloadedmetadata", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onloadedmetadata", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onloadend", typeof(Microsoft.AspNetCore.Components.Web.ProgressEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onloadend", typeof(Microsoft.AspNetCore.Components.Web.ProgressEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onloadstart", typeof(Microsoft.AspNetCore.Components.Web.ProgressEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onloadstart", typeof(Microsoft.AspNetCore.Components.Web.ProgressEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onlostpointercapture", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onlostpointercapture", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onmousedown", typeof(Microsoft.AspNetCore.Components.Web.MouseEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onmousedown", typeof(Microsoft.AspNetCore.Components.Web.MouseEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onmousemove", typeof(Microsoft.AspNetCore.Components.Web.MouseEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onmousemove", typeof(Microsoft.AspNetCore.Components.Web.MouseEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onmouseout", typeof(Microsoft.AspNetCore.Components.Web.MouseEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onmouseout", typeof(Microsoft.AspNetCore.Components.Web.MouseEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onmouseover", typeof(Microsoft.AspNetCore.Components.Web.MouseEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onmouseover", typeof(Microsoft.AspNetCore.Components.Web.MouseEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onmouseup", typeof(Microsoft.AspNetCore.Components.Web.MouseEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onmouseup", typeof(Microsoft.AspNetCore.Components.Web.MouseEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onmousewheel", typeof(Microsoft.AspNetCore.Components.Web.WheelEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onmousewheel", typeof(Microsoft.AspNetCore.Components.Web.WheelEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpaste", typeof(Microsoft.AspNetCore.Components.Web.ClipboardEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpaste", typeof(Microsoft.AspNetCore.Components.Web.ClipboardEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpause", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpause", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onplay", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onplay", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onplaying", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onplaying", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointercancel", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointercancel", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointerdown", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointerdown", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointerenter", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointerenter", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointerleave", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointerleave", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointerlockchange", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointerlockchange", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointerlockerror", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointerlockerror", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointermove", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointermove", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointerout", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointerout", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointerover", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointerover", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointerup", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointerup", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onprogress", typeof(Microsoft.AspNetCore.Components.Web.ProgressEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onprogress", typeof(Microsoft.AspNetCore.Components.Web.ProgressEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onratechange", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onratechange", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onreadystatechange", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onreadystatechange", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onreset", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onreset", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onscroll", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onscroll", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onseeked", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onseeked", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onseeking", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onseeking", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onselect", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onselect", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onselectionchange", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onselectionchange", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onselectstart", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onselectstart", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onstalled", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onstalled", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onstop", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onstop", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onsubmit", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onsubmit", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onsuspend", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onsuspend", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ontimeout", typeof(Microsoft.AspNetCore.Components.Web.ProgressEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ontimeout", typeof(Microsoft.AspNetCore.Components.Web.ProgressEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ontimeupdate", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ontimeupdate", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ontouchcancel", typeof(Microsoft.AspNetCore.Components.Web.TouchEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ontouchcancel", typeof(Microsoft.AspNetCore.Components.Web.TouchEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ontouchend", typeof(Microsoft.AspNetCore.Components.Web.TouchEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ontouchend", typeof(Microsoft.AspNetCore.Components.Web.TouchEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ontouchenter", typeof(Microsoft.AspNetCore.Components.Web.TouchEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ontouchenter", typeof(Microsoft.AspNetCore.Components.Web.TouchEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ontouchleave", typeof(Microsoft.AspNetCore.Components.Web.TouchEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ontouchleave", typeof(Microsoft.AspNetCore.Components.Web.TouchEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ontouchmove", typeof(Microsoft.AspNetCore.Components.Web.TouchEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ontouchmove", typeof(Microsoft.AspNetCore.Components.Web.TouchEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ontouchstart", typeof(Microsoft.AspNetCore.Components.Web.TouchEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ontouchstart", typeof(Microsoft.AspNetCore.Components.Web.TouchEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onvolumechange", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onvolumechange", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onwaiting", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onwaiting", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onwheel", typeof(Microsoft.AspNetCore.Components.Web.WheelEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onwheel", typeof(Microsoft.AspNetCore.Components.Web.WheelEventArgs), true, true)]
|
||||||
public static partial class EventHandlers
|
public static partial class EventHandlers
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -125,6 +125,8 @@ namespace Microsoft.AspNetCore.Components.Forms
|
||||||
public ValidationSummary() { }
|
public ValidationSummary() { }
|
||||||
[Microsoft.AspNetCore.Components.ParameterAttribute(CaptureUnmatchedValues=true)]
|
[Microsoft.AspNetCore.Components.ParameterAttribute(CaptureUnmatchedValues=true)]
|
||||||
public System.Collections.Generic.IReadOnlyDictionary<string, object> AdditionalAttributes { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
public System.Collections.Generic.IReadOnlyDictionary<string, object> AdditionalAttributes { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||||
|
[Microsoft.AspNetCore.Components.ParameterAttribute]
|
||||||
|
public object Model { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||||
protected override void BuildRenderTree(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder builder) { }
|
protected override void BuildRenderTree(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder builder) { }
|
||||||
protected virtual void Dispose(bool disposing) { }
|
protected virtual void Dispose(bool disposing) { }
|
||||||
protected override void OnParametersSet() { }
|
protected override void OnParametersSet() { }
|
||||||
|
|
@ -222,97 +224,97 @@ namespace Microsoft.AspNetCore.Components.Web
|
||||||
public string Message { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
public string Message { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||||
public string Type { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
public string Type { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||||
}
|
}
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onabort", typeof(Microsoft.AspNetCore.Components.Web.ProgressEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onabort", typeof(Microsoft.AspNetCore.Components.Web.ProgressEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onactivate", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onactivate", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onbeforeactivate", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onbeforeactivate", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onbeforecopy", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onbeforecopy", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onbeforecut", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onbeforecut", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onbeforedeactivate", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onbeforedeactivate", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onbeforepaste", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onbeforepaste", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onblur", typeof(Microsoft.AspNetCore.Components.Web.FocusEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onblur", typeof(Microsoft.AspNetCore.Components.Web.FocusEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("oncanplay", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("oncanplay", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("oncanplaythrough", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("oncanplaythrough", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onchange", typeof(Microsoft.AspNetCore.Components.ChangeEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onchange", typeof(Microsoft.AspNetCore.Components.ChangeEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onclick", typeof(Microsoft.AspNetCore.Components.Web.MouseEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onclick", typeof(Microsoft.AspNetCore.Components.Web.MouseEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("oncontextmenu", typeof(Microsoft.AspNetCore.Components.Web.MouseEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("oncontextmenu", typeof(Microsoft.AspNetCore.Components.Web.MouseEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("oncopy", typeof(Microsoft.AspNetCore.Components.Web.ClipboardEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("oncopy", typeof(Microsoft.AspNetCore.Components.Web.ClipboardEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("oncuechange", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("oncuechange", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("oncut", typeof(Microsoft.AspNetCore.Components.Web.ClipboardEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("oncut", typeof(Microsoft.AspNetCore.Components.Web.ClipboardEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondblclick", typeof(Microsoft.AspNetCore.Components.Web.MouseEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondblclick", typeof(Microsoft.AspNetCore.Components.Web.MouseEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondeactivate", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondeactivate", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondrag", typeof(Microsoft.AspNetCore.Components.Web.DragEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondrag", typeof(Microsoft.AspNetCore.Components.Web.DragEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondragend", typeof(Microsoft.AspNetCore.Components.Web.DragEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondragend", typeof(Microsoft.AspNetCore.Components.Web.DragEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondragenter", typeof(Microsoft.AspNetCore.Components.Web.DragEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondragenter", typeof(Microsoft.AspNetCore.Components.Web.DragEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondragleave", typeof(Microsoft.AspNetCore.Components.Web.DragEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondragleave", typeof(Microsoft.AspNetCore.Components.Web.DragEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondragover", typeof(Microsoft.AspNetCore.Components.Web.DragEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondragover", typeof(Microsoft.AspNetCore.Components.Web.DragEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondragstart", typeof(Microsoft.AspNetCore.Components.Web.DragEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondragstart", typeof(Microsoft.AspNetCore.Components.Web.DragEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondrop", typeof(Microsoft.AspNetCore.Components.Web.DragEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondrop", typeof(Microsoft.AspNetCore.Components.Web.DragEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondurationchange", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondurationchange", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onemptied", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onemptied", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onended", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onended", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onerror", typeof(Microsoft.AspNetCore.Components.Web.ErrorEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onerror", typeof(Microsoft.AspNetCore.Components.Web.ErrorEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onfocus", typeof(Microsoft.AspNetCore.Components.Web.FocusEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onfocus", typeof(Microsoft.AspNetCore.Components.Web.FocusEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onfocusin", typeof(Microsoft.AspNetCore.Components.Web.FocusEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onfocusin", typeof(Microsoft.AspNetCore.Components.Web.FocusEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onfocusout", typeof(Microsoft.AspNetCore.Components.Web.FocusEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onfocusout", typeof(Microsoft.AspNetCore.Components.Web.FocusEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onfullscreenchange", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onfullscreenchange", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onfullscreenerror", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onfullscreenerror", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ongotpointercapture", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ongotpointercapture", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("oninput", typeof(Microsoft.AspNetCore.Components.ChangeEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("oninput", typeof(Microsoft.AspNetCore.Components.ChangeEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("oninvalid", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("oninvalid", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onkeydown", typeof(Microsoft.AspNetCore.Components.Web.KeyboardEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onkeydown", typeof(Microsoft.AspNetCore.Components.Web.KeyboardEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onkeypress", typeof(Microsoft.AspNetCore.Components.Web.KeyboardEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onkeypress", typeof(Microsoft.AspNetCore.Components.Web.KeyboardEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onkeyup", typeof(Microsoft.AspNetCore.Components.Web.KeyboardEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onkeyup", typeof(Microsoft.AspNetCore.Components.Web.KeyboardEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onload", typeof(Microsoft.AspNetCore.Components.Web.ProgressEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onload", typeof(Microsoft.AspNetCore.Components.Web.ProgressEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onloadeddata", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onloadeddata", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onloadedmetadata", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onloadedmetadata", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onloadend", typeof(Microsoft.AspNetCore.Components.Web.ProgressEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onloadend", typeof(Microsoft.AspNetCore.Components.Web.ProgressEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onloadstart", typeof(Microsoft.AspNetCore.Components.Web.ProgressEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onloadstart", typeof(Microsoft.AspNetCore.Components.Web.ProgressEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onlostpointercapture", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onlostpointercapture", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onmousedown", typeof(Microsoft.AspNetCore.Components.Web.MouseEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onmousedown", typeof(Microsoft.AspNetCore.Components.Web.MouseEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onmousemove", typeof(Microsoft.AspNetCore.Components.Web.MouseEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onmousemove", typeof(Microsoft.AspNetCore.Components.Web.MouseEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onmouseout", typeof(Microsoft.AspNetCore.Components.Web.MouseEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onmouseout", typeof(Microsoft.AspNetCore.Components.Web.MouseEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onmouseover", typeof(Microsoft.AspNetCore.Components.Web.MouseEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onmouseover", typeof(Microsoft.AspNetCore.Components.Web.MouseEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onmouseup", typeof(Microsoft.AspNetCore.Components.Web.MouseEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onmouseup", typeof(Microsoft.AspNetCore.Components.Web.MouseEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onmousewheel", typeof(Microsoft.AspNetCore.Components.Web.WheelEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onmousewheel", typeof(Microsoft.AspNetCore.Components.Web.WheelEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpaste", typeof(Microsoft.AspNetCore.Components.Web.ClipboardEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpaste", typeof(Microsoft.AspNetCore.Components.Web.ClipboardEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpause", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpause", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onplay", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onplay", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onplaying", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onplaying", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointercancel", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointercancel", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointerdown", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointerdown", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointerenter", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointerenter", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointerleave", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointerleave", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointerlockchange", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointerlockchange", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointerlockerror", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointerlockerror", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointermove", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointermove", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointerout", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointerout", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointerover", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointerover", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointerup", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointerup", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onprogress", typeof(Microsoft.AspNetCore.Components.Web.ProgressEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onprogress", typeof(Microsoft.AspNetCore.Components.Web.ProgressEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onratechange", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onratechange", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onreadystatechange", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onreadystatechange", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onreset", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onreset", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onscroll", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onscroll", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onseeked", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onseeked", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onseeking", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onseeking", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onselect", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onselect", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onselectionchange", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onselectionchange", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onselectstart", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onselectstart", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onstalled", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onstalled", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onstop", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onstop", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onsubmit", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onsubmit", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onsuspend", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onsuspend", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ontimeout", typeof(Microsoft.AspNetCore.Components.Web.ProgressEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ontimeout", typeof(Microsoft.AspNetCore.Components.Web.ProgressEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ontimeupdate", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ontimeupdate", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ontouchcancel", typeof(Microsoft.AspNetCore.Components.Web.TouchEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ontouchcancel", typeof(Microsoft.AspNetCore.Components.Web.TouchEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ontouchend", typeof(Microsoft.AspNetCore.Components.Web.TouchEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ontouchend", typeof(Microsoft.AspNetCore.Components.Web.TouchEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ontouchenter", typeof(Microsoft.AspNetCore.Components.Web.TouchEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ontouchenter", typeof(Microsoft.AspNetCore.Components.Web.TouchEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ontouchleave", typeof(Microsoft.AspNetCore.Components.Web.TouchEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ontouchleave", typeof(Microsoft.AspNetCore.Components.Web.TouchEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ontouchmove", typeof(Microsoft.AspNetCore.Components.Web.TouchEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ontouchmove", typeof(Microsoft.AspNetCore.Components.Web.TouchEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ontouchstart", typeof(Microsoft.AspNetCore.Components.Web.TouchEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ontouchstart", typeof(Microsoft.AspNetCore.Components.Web.TouchEventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onvolumechange", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onvolumechange", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onwaiting", typeof(System.EventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onwaiting", typeof(System.EventArgs), true, true)]
|
||||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onwheel", typeof(Microsoft.AspNetCore.Components.Web.WheelEventArgs))]
|
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onwheel", typeof(Microsoft.AspNetCore.Components.Web.WheelEventArgs), true, true)]
|
||||||
public static partial class EventHandlers
|
public static partial class EventHandlers
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,12 @@ namespace Microsoft.AspNetCore.Components.Forms
|
||||||
private EditContext _previousEditContext;
|
private EditContext _previousEditContext;
|
||||||
private readonly EventHandler<ValidationStateChangedEventArgs> _validationStateChangedHandler;
|
private readonly EventHandler<ValidationStateChangedEventArgs> _validationStateChangedHandler;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the model to produce the list of validation messages for.
|
||||||
|
/// When specified, this lists all errors that are associated with the model instance.
|
||||||
|
/// </summary>
|
||||||
|
[Parameter] public object Model { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets a collection of additional attributes that will be applied to the created <c>ul</c> element.
|
/// Gets or sets a collection of additional attributes that will be applied to the created <c>ul</c> element.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -57,22 +63,31 @@ namespace Microsoft.AspNetCore.Components.Forms
|
||||||
{
|
{
|
||||||
// As an optimization, only evaluate the messages enumerable once, and
|
// As an optimization, only evaluate the messages enumerable once, and
|
||||||
// only produce the enclosing <ul> if there's at least one message
|
// only produce the enclosing <ul> if there's at least one message
|
||||||
var messagesEnumerator = CurrentEditContext.GetValidationMessages().GetEnumerator();
|
var validationMessages = Model is null ?
|
||||||
if (messagesEnumerator.MoveNext())
|
CurrentEditContext.GetValidationMessages() :
|
||||||
|
CurrentEditContext.GetValidationMessages(new FieldIdentifier(Model, string.Empty));
|
||||||
|
|
||||||
|
var first = true;
|
||||||
|
foreach (var error in validationMessages)
|
||||||
{
|
{
|
||||||
|
if (first)
|
||||||
|
{
|
||||||
|
first = false;
|
||||||
|
|
||||||
builder.OpenElement(0, "ul");
|
builder.OpenElement(0, "ul");
|
||||||
builder.AddMultipleAttributes(1, AdditionalAttributes);
|
builder.AddMultipleAttributes(1, AdditionalAttributes);
|
||||||
builder.AddAttribute(2, "class", "validation-errors");
|
builder.AddAttribute(2, "class", "validation-errors");
|
||||||
|
}
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
builder.OpenElement(3, "li");
|
builder.OpenElement(3, "li");
|
||||||
builder.AddAttribute(4, "class", "validation-message");
|
builder.AddAttribute(4, "class", "validation-message");
|
||||||
builder.AddContent(5, messagesEnumerator.Current);
|
builder.AddContent(5, error);
|
||||||
builder.CloseElement();
|
builder.CloseElement();
|
||||||
}
|
}
|
||||||
while (messagesEnumerator.MoveNext());
|
|
||||||
|
|
||||||
|
if (!first)
|
||||||
|
{
|
||||||
|
// We have at least one validation message.
|
||||||
builder.CloseElement();
|
builder.CloseElement();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,117 +11,117 @@ namespace Microsoft.AspNetCore.Components.Web
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
||||||
// Focus events
|
// Focus events
|
||||||
[EventHandler("onfocus", typeof(FocusEventArgs))]
|
[EventHandler("onfocus", typeof(FocusEventArgs), true, true)]
|
||||||
[EventHandler("onblur", typeof(FocusEventArgs))]
|
[EventHandler("onblur", typeof(FocusEventArgs), true, true)]
|
||||||
[EventHandler("onfocusin", typeof(FocusEventArgs))]
|
[EventHandler("onfocusin", typeof(FocusEventArgs), true, true)]
|
||||||
[EventHandler("onfocusout", typeof(FocusEventArgs))]
|
[EventHandler("onfocusout", typeof(FocusEventArgs), true, true)]
|
||||||
|
|
||||||
// Mouse events
|
// Mouse events
|
||||||
[EventHandler("onmouseover", typeof(MouseEventArgs))]
|
[EventHandler("onmouseover", typeof(MouseEventArgs), true, true)]
|
||||||
[EventHandler("onmouseout", typeof(MouseEventArgs))]
|
[EventHandler("onmouseout", typeof(MouseEventArgs), true, true)]
|
||||||
[EventHandler("onmousemove", typeof(MouseEventArgs))]
|
[EventHandler("onmousemove", typeof(MouseEventArgs), true, true)]
|
||||||
[EventHandler("onmousedown", typeof(MouseEventArgs))]
|
[EventHandler("onmousedown", typeof(MouseEventArgs), true, true)]
|
||||||
[EventHandler("onmouseup", typeof(MouseEventArgs))]
|
[EventHandler("onmouseup", typeof(MouseEventArgs), true, true)]
|
||||||
[EventHandler("onclick", typeof(MouseEventArgs))]
|
[EventHandler("onclick", typeof(MouseEventArgs), true, true)]
|
||||||
[EventHandler("ondblclick", typeof(MouseEventArgs))]
|
[EventHandler("ondblclick", typeof(MouseEventArgs), true, true)]
|
||||||
[EventHandler("onwheel", typeof(WheelEventArgs))]
|
[EventHandler("onwheel", typeof(WheelEventArgs), true, true)]
|
||||||
[EventHandler("onmousewheel", typeof(WheelEventArgs))]
|
[EventHandler("onmousewheel", typeof(WheelEventArgs), true, true)]
|
||||||
[EventHandler("oncontextmenu", typeof(MouseEventArgs))]
|
[EventHandler("oncontextmenu", typeof(MouseEventArgs), true, true)]
|
||||||
|
|
||||||
// Drag events
|
// Drag events
|
||||||
[EventHandler("ondrag", typeof(DragEventArgs))]
|
[EventHandler("ondrag", typeof(DragEventArgs), true, true)]
|
||||||
[EventHandler("ondragend", typeof(DragEventArgs))]
|
[EventHandler("ondragend", typeof(DragEventArgs), true, true)]
|
||||||
[EventHandler("ondragenter", typeof(DragEventArgs))]
|
[EventHandler("ondragenter", typeof(DragEventArgs), true, true)]
|
||||||
[EventHandler("ondragleave", typeof(DragEventArgs))]
|
[EventHandler("ondragleave", typeof(DragEventArgs), true, true)]
|
||||||
[EventHandler("ondragover", typeof(DragEventArgs))]
|
[EventHandler("ondragover", typeof(DragEventArgs), true, true)]
|
||||||
[EventHandler("ondragstart", typeof(DragEventArgs))]
|
[EventHandler("ondragstart", typeof(DragEventArgs), true, true)]
|
||||||
[EventHandler("ondrop", typeof(DragEventArgs))]
|
[EventHandler("ondrop", typeof(DragEventArgs), true, true)]
|
||||||
|
|
||||||
// Keyboard events
|
// Keyboard events
|
||||||
[EventHandler("onkeydown", typeof(KeyboardEventArgs))]
|
[EventHandler("onkeydown", typeof(KeyboardEventArgs), true, true)]
|
||||||
[EventHandler("onkeyup", typeof(KeyboardEventArgs))]
|
[EventHandler("onkeyup", typeof(KeyboardEventArgs), true, true)]
|
||||||
[EventHandler("onkeypress", typeof(KeyboardEventArgs))]
|
[EventHandler("onkeypress", typeof(KeyboardEventArgs), true, true)]
|
||||||
|
|
||||||
// Input events
|
// Input events
|
||||||
[EventHandler("onchange", typeof(ChangeEventArgs))]
|
[EventHandler("onchange", typeof(ChangeEventArgs), true, true)]
|
||||||
[EventHandler("oninput", typeof(ChangeEventArgs))]
|
[EventHandler("oninput", typeof(ChangeEventArgs), true, true)]
|
||||||
[EventHandler("oninvalid", typeof(EventArgs))]
|
[EventHandler("oninvalid", typeof(EventArgs), true, true)]
|
||||||
[EventHandler("onreset", typeof(EventArgs))]
|
[EventHandler("onreset", typeof(EventArgs), true, true)]
|
||||||
[EventHandler("onselect", typeof(EventArgs))]
|
[EventHandler("onselect", typeof(EventArgs), true, true)]
|
||||||
[EventHandler("onselectstart", typeof(EventArgs))]
|
[EventHandler("onselectstart", typeof(EventArgs), true, true)]
|
||||||
[EventHandler("onselectionchange", typeof(EventArgs))]
|
[EventHandler("onselectionchange", typeof(EventArgs), true, true)]
|
||||||
[EventHandler("onsubmit", typeof(EventArgs))]
|
[EventHandler("onsubmit", typeof(EventArgs), true, true)]
|
||||||
|
|
||||||
// Clipboard events
|
// Clipboard events
|
||||||
[EventHandler("onbeforecopy", typeof(EventArgs))]
|
[EventHandler("onbeforecopy", typeof(EventArgs), true, true)]
|
||||||
[EventHandler("onbeforecut", typeof(EventArgs))]
|
[EventHandler("onbeforecut", typeof(EventArgs), true, true)]
|
||||||
[EventHandler("onbeforepaste", typeof(EventArgs))]
|
[EventHandler("onbeforepaste", typeof(EventArgs), true, true)]
|
||||||
[EventHandler("oncopy", typeof(ClipboardEventArgs))]
|
[EventHandler("oncopy", typeof(ClipboardEventArgs), true, true)]
|
||||||
[EventHandler("oncut", typeof(ClipboardEventArgs))]
|
[EventHandler("oncut", typeof(ClipboardEventArgs), true, true)]
|
||||||
[EventHandler("onpaste", typeof(ClipboardEventArgs))]
|
[EventHandler("onpaste", typeof(ClipboardEventArgs), true, true)]
|
||||||
|
|
||||||
// Touch events
|
// Touch events
|
||||||
[EventHandler("ontouchcancel", typeof(TouchEventArgs))]
|
[EventHandler("ontouchcancel", typeof(TouchEventArgs), true, true)]
|
||||||
[EventHandler("ontouchend", typeof(TouchEventArgs))]
|
[EventHandler("ontouchend", typeof(TouchEventArgs), true, true)]
|
||||||
[EventHandler("ontouchmove", typeof(TouchEventArgs))]
|
[EventHandler("ontouchmove", typeof(TouchEventArgs), true, true)]
|
||||||
[EventHandler("ontouchstart", typeof(TouchEventArgs))]
|
[EventHandler("ontouchstart", typeof(TouchEventArgs), true, true)]
|
||||||
[EventHandler("ontouchenter", typeof(TouchEventArgs))]
|
[EventHandler("ontouchenter", typeof(TouchEventArgs), true, true)]
|
||||||
[EventHandler("ontouchleave", typeof(TouchEventArgs))]
|
[EventHandler("ontouchleave", typeof(TouchEventArgs), true, true)]
|
||||||
|
|
||||||
// Pointer events
|
// Pointer events
|
||||||
[EventHandler("ongotpointercapture", typeof(PointerEventArgs))]
|
[EventHandler("ongotpointercapture", typeof(PointerEventArgs), true, true)]
|
||||||
[EventHandler("onlostpointercapture", typeof(PointerEventArgs))]
|
[EventHandler("onlostpointercapture", typeof(PointerEventArgs), true, true)]
|
||||||
[EventHandler("onpointercancel", typeof(PointerEventArgs))]
|
[EventHandler("onpointercancel", typeof(PointerEventArgs), true, true)]
|
||||||
[EventHandler("onpointerdown", typeof(PointerEventArgs))]
|
[EventHandler("onpointerdown", typeof(PointerEventArgs), true, true)]
|
||||||
[EventHandler("onpointerenter", typeof(PointerEventArgs))]
|
[EventHandler("onpointerenter", typeof(PointerEventArgs), true, true)]
|
||||||
[EventHandler("onpointerleave", typeof(PointerEventArgs))]
|
[EventHandler("onpointerleave", typeof(PointerEventArgs), true, true)]
|
||||||
[EventHandler("onpointermove", typeof(PointerEventArgs))]
|
[EventHandler("onpointermove", typeof(PointerEventArgs), true, true)]
|
||||||
[EventHandler("onpointerout", typeof(PointerEventArgs))]
|
[EventHandler("onpointerout", typeof(PointerEventArgs), true, true)]
|
||||||
[EventHandler("onpointerover", typeof(PointerEventArgs))]
|
[EventHandler("onpointerover", typeof(PointerEventArgs), true, true)]
|
||||||
[EventHandler("onpointerup", typeof(PointerEventArgs))]
|
[EventHandler("onpointerup", typeof(PointerEventArgs), true, true)]
|
||||||
|
|
||||||
// Media events
|
// Media events
|
||||||
[EventHandler("oncanplay", typeof(EventArgs))]
|
[EventHandler("oncanplay", typeof(EventArgs), true, true)]
|
||||||
[EventHandler("oncanplaythrough", typeof(EventArgs))]
|
[EventHandler("oncanplaythrough", typeof(EventArgs), true, true)]
|
||||||
[EventHandler("oncuechange", typeof(EventArgs))]
|
[EventHandler("oncuechange", typeof(EventArgs), true, true)]
|
||||||
[EventHandler("ondurationchange", typeof(EventArgs))]
|
[EventHandler("ondurationchange", typeof(EventArgs), true, true)]
|
||||||
[EventHandler("onemptied", typeof(EventArgs))]
|
[EventHandler("onemptied", typeof(EventArgs), true, true)]
|
||||||
[EventHandler("onpause", typeof(EventArgs))]
|
[EventHandler("onpause", typeof(EventArgs), true, true)]
|
||||||
[EventHandler("onplay", typeof(EventArgs))]
|
[EventHandler("onplay", typeof(EventArgs), true, true)]
|
||||||
[EventHandler("onplaying", typeof(EventArgs))]
|
[EventHandler("onplaying", typeof(EventArgs), true, true)]
|
||||||
[EventHandler("onratechange", typeof(EventArgs))]
|
[EventHandler("onratechange", typeof(EventArgs), true, true)]
|
||||||
[EventHandler("onseeked", typeof(EventArgs))]
|
[EventHandler("onseeked", typeof(EventArgs), true, true)]
|
||||||
[EventHandler("onseeking", typeof(EventArgs))]
|
[EventHandler("onseeking", typeof(EventArgs), true, true)]
|
||||||
[EventHandler("onstalled", typeof(EventArgs))]
|
[EventHandler("onstalled", typeof(EventArgs), true, true)]
|
||||||
[EventHandler("onstop", typeof(EventArgs))]
|
[EventHandler("onstop", typeof(EventArgs), true, true)]
|
||||||
[EventHandler("onsuspend", typeof(EventArgs))]
|
[EventHandler("onsuspend", typeof(EventArgs), true, true)]
|
||||||
[EventHandler("ontimeupdate", typeof(EventArgs))]
|
[EventHandler("ontimeupdate", typeof(EventArgs), true, true)]
|
||||||
[EventHandler("onvolumechange", typeof(EventArgs))]
|
[EventHandler("onvolumechange", typeof(EventArgs), true, true)]
|
||||||
[EventHandler("onwaiting", typeof(EventArgs))]
|
[EventHandler("onwaiting", typeof(EventArgs), true, true)]
|
||||||
|
|
||||||
// Progress events
|
// Progress events
|
||||||
[EventHandler("onloadstart", typeof(ProgressEventArgs))]
|
[EventHandler("onloadstart", typeof(ProgressEventArgs), true, true)]
|
||||||
[EventHandler("ontimeout", typeof(ProgressEventArgs))]
|
[EventHandler("ontimeout", typeof(ProgressEventArgs), true, true)]
|
||||||
[EventHandler("onabort", typeof(ProgressEventArgs))]
|
[EventHandler("onabort", typeof(ProgressEventArgs), true, true)]
|
||||||
[EventHandler("onload", typeof(ProgressEventArgs))]
|
[EventHandler("onload", typeof(ProgressEventArgs), true, true)]
|
||||||
[EventHandler("onloadend", typeof(ProgressEventArgs))]
|
[EventHandler("onloadend", typeof(ProgressEventArgs), true, true)]
|
||||||
[EventHandler("onprogress", typeof(ProgressEventArgs))]
|
[EventHandler("onprogress", typeof(ProgressEventArgs), true, true)]
|
||||||
[EventHandler("onerror", typeof(ErrorEventArgs))]
|
[EventHandler("onerror", typeof(ErrorEventArgs), true, true)]
|
||||||
|
|
||||||
// General events
|
// General events
|
||||||
[EventHandler("onactivate", typeof(EventArgs))]
|
[EventHandler("onactivate", typeof(EventArgs), true, true)]
|
||||||
[EventHandler("onbeforeactivate", typeof(EventArgs))]
|
[EventHandler("onbeforeactivate", typeof(EventArgs), true, true)]
|
||||||
[EventHandler("onbeforedeactivate", typeof(EventArgs))]
|
[EventHandler("onbeforedeactivate", typeof(EventArgs), true, true)]
|
||||||
[EventHandler("ondeactivate", typeof(EventArgs))]
|
[EventHandler("ondeactivate", typeof(EventArgs), true, true)]
|
||||||
[EventHandler("onended", typeof(EventArgs))]
|
[EventHandler("onended", typeof(EventArgs), true, true)]
|
||||||
[EventHandler("onfullscreenchange", typeof(EventArgs))]
|
[EventHandler("onfullscreenchange", typeof(EventArgs), true, true)]
|
||||||
[EventHandler("onfullscreenerror", typeof(EventArgs))]
|
[EventHandler("onfullscreenerror", typeof(EventArgs), true, true)]
|
||||||
[EventHandler("onloadeddata", typeof(EventArgs))]
|
[EventHandler("onloadeddata", typeof(EventArgs), true, true)]
|
||||||
[EventHandler("onloadedmetadata", typeof(EventArgs))]
|
[EventHandler("onloadedmetadata", typeof(EventArgs), true, true)]
|
||||||
[EventHandler("onpointerlockchange", typeof(EventArgs))]
|
[EventHandler("onpointerlockchange", typeof(EventArgs), true, true)]
|
||||||
[EventHandler("onpointerlockerror", typeof(EventArgs))]
|
[EventHandler("onpointerlockerror", typeof(EventArgs), true, true)]
|
||||||
[EventHandler("onreadystatechange", typeof(EventArgs))]
|
[EventHandler("onreadystatechange", typeof(EventArgs), true, true)]
|
||||||
[EventHandler("onscroll", typeof(EventArgs))]
|
[EventHandler("onscroll", typeof(EventArgs), true, true)]
|
||||||
public static class EventHandlers
|
public static class EventHandlers
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var expectedError = $"There was an unhandled exception on the current circuit, so this circuit will be terminated. For more details turn on " +
|
var expectedError = $"There was an unhandled exception on the current circuit, so this circuit will be terminated. For more details turn on " +
|
||||||
$"detailed exceptions in 'CircuitOptions.DetailedErrors'. Bad input data.";
|
$"detailed exceptions by setting 'DetailedErrors: true' in 'appSettings.Development.json' or set 'CircuitOptions.DetailedErrors'. Bad input data.";
|
||||||
|
|
||||||
var eventDescriptor = Serialize(new WebEventDescriptor()
|
var eventDescriptor = Serialize(new WebEventDescriptor()
|
||||||
{
|
{
|
||||||
|
|
@ -65,7 +65,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var expectedError = $"There was an unhandled exception on the current circuit, so this circuit will be terminated. For more details turn on " +
|
var expectedError = $"There was an unhandled exception on the current circuit, so this circuit will be terminated. For more details turn on " +
|
||||||
$"detailed exceptions in 'CircuitOptions.DetailedErrors'. Failed to dispatch event.";
|
$"detailed exceptions by setting 'DetailedErrors: true' in 'appSettings.Development.json' or set 'CircuitOptions.DetailedErrors'. Failed to dispatch event.";
|
||||||
|
|
||||||
var eventDescriptor = Serialize(new WebEventDescriptor()
|
var eventDescriptor = Serialize(new WebEventDescriptor()
|
||||||
{
|
{
|
||||||
|
|
@ -105,7 +105,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var expectedError = $"There was an unhandled exception on the current circuit, so this circuit will be terminated. For more details turn on " +
|
var expectedError = $"There was an unhandled exception on the current circuit, so this circuit will be terminated. For more details turn on " +
|
||||||
$"detailed exceptions in 'CircuitOptions.DetailedErrors'. Failed to complete render batch '1846'.";
|
$"detailed exceptions by setting 'DetailedErrors: true' in 'appSettings.Development.json' or set 'CircuitOptions.DetailedErrors'. Failed to complete render batch '1846'.";
|
||||||
|
|
||||||
|
|
||||||
Client.ConfirmRenderBatch = false;
|
Client.ConfirmRenderBatch = false;
|
||||||
|
|
|
||||||
|
|
@ -216,7 +216,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var expectedError = "There was an unhandled exception on the current circuit, so this circuit will be terminated. " +
|
var expectedError = "There was an unhandled exception on the current circuit, so this circuit will be terminated. " +
|
||||||
"For more details turn on detailed exceptions in 'CircuitOptions.DetailedErrors'. " +
|
"For more details turn on detailed exceptions by setting 'DetailedErrors: true' in 'appSettings.Development.json' or set 'CircuitOptions.DetailedErrors'. " +
|
||||||
"Location change to 'http://example.com' failed.";
|
"Location change to 'http://example.com' failed.";
|
||||||
|
|
||||||
var rootUri = ServerFixture.RootUri;
|
var rootUri = ServerFixture.RootUri;
|
||||||
|
|
@ -245,7 +245,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var expectedError = "There was an unhandled exception on the current circuit, so this circuit will be terminated. " +
|
var expectedError = "There was an unhandled exception on the current circuit, so this circuit will be terminated. " +
|
||||||
"For more details turn on detailed exceptions in 'CircuitOptions.DetailedErrors'. " +
|
"For more details turn on detailed exceptions by setting 'DetailedErrors: true' in 'appSettings.Development.json' or set 'CircuitOptions.DetailedErrors'. " +
|
||||||
"Location change failed.";
|
"Location change failed.";
|
||||||
|
|
||||||
var rootUri = ServerFixture.RootUri;
|
var rootUri = ServerFixture.RootUri;
|
||||||
|
|
|
||||||
|
|
@ -75,11 +75,6 @@ namespace Microsoft.AspNetCore.Components
|
||||||
|
|
||||||
async Task IAsyncLifetime.DisposeAsync()
|
async Task IAsyncLifetime.DisposeAsync()
|
||||||
{
|
{
|
||||||
if (TestSink != null)
|
|
||||||
{
|
|
||||||
TestSink.MessageLogged -= TestSink_MessageLogged;
|
|
||||||
}
|
|
||||||
|
|
||||||
await DisposeAsync();
|
await DisposeAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -90,6 +85,11 @@ namespace Microsoft.AspNetCore.Components
|
||||||
|
|
||||||
protected virtual Task DisposeAsync()
|
protected virtual Task DisposeAsync()
|
||||||
{
|
{
|
||||||
|
if (TestSink != null)
|
||||||
|
{
|
||||||
|
TestSink.MessageLogged -= TestSink_MessageLogged;
|
||||||
|
}
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -97,8 +97,19 @@ namespace Microsoft.AspNetCore.Components
|
||||||
{
|
{
|
||||||
var log = new LogMessage(context.LogLevel, context.EventId, context.Message, context.Exception);
|
var log = new LogMessage(context.LogLevel, context.EventId, context.Message, context.Exception);
|
||||||
Logs.Enqueue(log);
|
Logs.Enqueue(log);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// This might produce an InvalidOperationException when the logger tries to log a message after
|
||||||
|
// the test has completed but before the handler has been removed.
|
||||||
|
// ---> System.InvalidOperationException: There is no currently active test.
|
||||||
|
// For that reason, we capture the exception here and silence it, as the message is captured inside the Logs
|
||||||
|
// variable anyway.
|
||||||
Output.WriteLine(log.ToString());
|
Output.WriteLine(log.ToString());
|
||||||
}
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[DebuggerDisplay("{LogLevel.ToString(),nq} - {Message ?? \"null\",nq} - {Exception?.Message,nq}")]
|
[DebuggerDisplay("{LogLevel.ToString(),nq} - {Message ?? \"null\",nq} - {Exception?.Message,nq}")]
|
||||||
protected sealed class LogMessage
|
protected sealed class LogMessage
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,17 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// 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.
|
// 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.Threading.Tasks;
|
||||||
using BasicTestApp;
|
using BasicTestApp;
|
||||||
using BasicTestApp.FormsTest;
|
using BasicTestApp.FormsTest;
|
||||||
using Microsoft.AspNetCore.Components.E2ETest.Infrastructure;
|
using Microsoft.AspNetCore.Components.E2ETest.Infrastructure;
|
||||||
using Microsoft.AspNetCore.Components.E2ETest.Infrastructure.ServerFixtures;
|
using Microsoft.AspNetCore.Components.E2ETest.Infrastructure.ServerFixtures;
|
||||||
using Microsoft.AspNetCore.E2ETesting;
|
using Microsoft.AspNetCore.E2ETesting;
|
||||||
using Microsoft.AspNetCore.Testing;
|
|
||||||
using OpenQA.Selenium;
|
using OpenQA.Selenium;
|
||||||
using OpenQA.Selenium.Support.UI;
|
using OpenQA.Selenium.Support.UI;
|
||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text.Json;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Xunit;
|
using Xunit;
|
||||||
using Xunit.Abstractions;
|
using Xunit.Abstractions;
|
||||||
|
|
||||||
|
|
@ -34,14 +33,20 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
|
||||||
Navigate(ServerPathBase, noReload: _serverFixture.ExecutionMode == ExecutionMode.Client);
|
Navigate(ServerPathBase, noReload: _serverFixture.ExecutionMode == ExecutionMode.Client);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected virtual IWebElement MountSimpleValidationComponent()
|
||||||
|
=> Browser.MountTestComponent<SimpleValidationComponent>();
|
||||||
|
|
||||||
|
protected virtual IWebElement MountTypicalValidationComponent()
|
||||||
|
=> Browser.MountTestComponent<TypicalValidationComponent>();
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task EditFormWorksWithDataAnnotationsValidator()
|
public async Task EditFormWorksWithDataAnnotationsValidator()
|
||||||
{
|
{
|
||||||
var appElement = Browser.MountTestComponent<SimpleValidationComponent>();
|
var appElement = MountSimpleValidationComponent();;
|
||||||
var form = appElement.FindElement(By.TagName("form"));
|
var form = appElement.FindElement(By.TagName("form"));
|
||||||
var userNameInput = appElement.FindElement(By.ClassName("user-name")).FindElement(By.TagName("input"));
|
var userNameInput = appElement.FindElement(By.ClassName("user-name")).FindElement(By.TagName("input"));
|
||||||
var acceptsTermsInput = appElement.FindElement(By.ClassName("accepts-terms")).FindElement(By.TagName("input"));
|
var acceptsTermsInput = appElement.FindElement(By.ClassName("accepts-terms")).FindElement(By.TagName("input"));
|
||||||
var submitButton = appElement.FindElement(By.TagName("button"));
|
var submitButton = appElement.FindElement(By.CssSelector("button[type=submit]"));
|
||||||
var messagesAccessor = CreateValidationMessagesAccessor(appElement);
|
var messagesAccessor = CreateValidationMessagesAccessor(appElement);
|
||||||
|
|
||||||
// The form emits unmatched attributes
|
// The form emits unmatched attributes
|
||||||
|
|
@ -77,7 +82,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
|
||||||
[Fact]
|
[Fact]
|
||||||
public void InputTextInteractsWithEditContext()
|
public void InputTextInteractsWithEditContext()
|
||||||
{
|
{
|
||||||
var appElement = Browser.MountTestComponent<TypicalValidationComponent>();
|
var appElement = MountTypicalValidationComponent();
|
||||||
var nameInput = appElement.FindElement(By.ClassName("name")).FindElement(By.TagName("input"));
|
var nameInput = appElement.FindElement(By.ClassName("name")).FindElement(By.TagName("input"));
|
||||||
var messagesAccessor = CreateValidationMessagesAccessor(appElement);
|
var messagesAccessor = CreateValidationMessagesAccessor(appElement);
|
||||||
|
|
||||||
|
|
@ -104,7 +109,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
|
||||||
[Fact]
|
[Fact]
|
||||||
public void InputNumberInteractsWithEditContext_NonNullableInt()
|
public void InputNumberInteractsWithEditContext_NonNullableInt()
|
||||||
{
|
{
|
||||||
var appElement = Browser.MountTestComponent<TypicalValidationComponent>();
|
var appElement = MountTypicalValidationComponent();
|
||||||
var ageInput = appElement.FindElement(By.ClassName("age")).FindElement(By.TagName("input"));
|
var ageInput = appElement.FindElement(By.ClassName("age")).FindElement(By.TagName("input"));
|
||||||
var messagesAccessor = CreateValidationMessagesAccessor(appElement);
|
var messagesAccessor = CreateValidationMessagesAccessor(appElement);
|
||||||
|
|
||||||
|
|
@ -136,7 +141,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
|
||||||
[Fact]
|
[Fact]
|
||||||
public void InputNumberInteractsWithEditContext_NullableFloat()
|
public void InputNumberInteractsWithEditContext_NullableFloat()
|
||||||
{
|
{
|
||||||
var appElement = Browser.MountTestComponent<TypicalValidationComponent>();
|
var appElement = MountTypicalValidationComponent();
|
||||||
var heightInput = appElement.FindElement(By.ClassName("height")).FindElement(By.TagName("input"));
|
var heightInput = appElement.FindElement(By.ClassName("height")).FindElement(By.TagName("input"));
|
||||||
var messagesAccessor = CreateValidationMessagesAccessor(appElement);
|
var messagesAccessor = CreateValidationMessagesAccessor(appElement);
|
||||||
|
|
||||||
|
|
@ -160,7 +165,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
|
||||||
[Fact]
|
[Fact]
|
||||||
public void InputTextAreaInteractsWithEditContext()
|
public void InputTextAreaInteractsWithEditContext()
|
||||||
{
|
{
|
||||||
var appElement = Browser.MountTestComponent<TypicalValidationComponent>();
|
var appElement = MountTypicalValidationComponent();
|
||||||
var descriptionInput = appElement.FindElement(By.ClassName("description")).FindElement(By.TagName("textarea"));
|
var descriptionInput = appElement.FindElement(By.ClassName("description")).FindElement(By.TagName("textarea"));
|
||||||
var messagesAccessor = CreateValidationMessagesAccessor(appElement);
|
var messagesAccessor = CreateValidationMessagesAccessor(appElement);
|
||||||
|
|
||||||
|
|
@ -187,7 +192,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
|
||||||
[Fact]
|
[Fact]
|
||||||
public void InputDateInteractsWithEditContext_NonNullableDateTime()
|
public void InputDateInteractsWithEditContext_NonNullableDateTime()
|
||||||
{
|
{
|
||||||
var appElement = Browser.MountTestComponent<TypicalValidationComponent>();
|
var appElement = MountTypicalValidationComponent();
|
||||||
var renewalDateInput = appElement.FindElement(By.ClassName("renewal-date")).FindElement(By.TagName("input"));
|
var renewalDateInput = appElement.FindElement(By.ClassName("renewal-date")).FindElement(By.TagName("input"));
|
||||||
var messagesAccessor = CreateValidationMessagesAccessor(appElement);
|
var messagesAccessor = CreateValidationMessagesAccessor(appElement);
|
||||||
|
|
||||||
|
|
@ -218,7 +223,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
|
||||||
[Fact]
|
[Fact]
|
||||||
public void InputDateInteractsWithEditContext_NullableDateTimeOffset()
|
public void InputDateInteractsWithEditContext_NullableDateTimeOffset()
|
||||||
{
|
{
|
||||||
var appElement = Browser.MountTestComponent<TypicalValidationComponent>();
|
var appElement = MountTypicalValidationComponent();
|
||||||
var expiryDateInput = appElement.FindElement(By.ClassName("expiry-date")).FindElement(By.TagName("input"));
|
var expiryDateInput = appElement.FindElement(By.ClassName("expiry-date")).FindElement(By.TagName("input"));
|
||||||
var messagesAccessor = CreateValidationMessagesAccessor(appElement);
|
var messagesAccessor = CreateValidationMessagesAccessor(appElement);
|
||||||
|
|
||||||
|
|
@ -241,7 +246,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
|
||||||
[Fact]
|
[Fact]
|
||||||
public void InputSelectInteractsWithEditContext()
|
public void InputSelectInteractsWithEditContext()
|
||||||
{
|
{
|
||||||
var appElement = Browser.MountTestComponent<TypicalValidationComponent>();
|
var appElement = MountTypicalValidationComponent();
|
||||||
var ticketClassInput = new SelectElement(appElement.FindElement(By.ClassName("ticket-class")).FindElement(By.TagName("select")));
|
var ticketClassInput = new SelectElement(appElement.FindElement(By.ClassName("ticket-class")).FindElement(By.TagName("select")));
|
||||||
var select = ticketClassInput.WrappedElement;
|
var select = ticketClassInput.WrappedElement;
|
||||||
var messagesAccessor = CreateValidationMessagesAccessor(appElement);
|
var messagesAccessor = CreateValidationMessagesAccessor(appElement);
|
||||||
|
|
@ -263,7 +268,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
|
||||||
[Fact]
|
[Fact]
|
||||||
public void InputCheckboxInteractsWithEditContext()
|
public void InputCheckboxInteractsWithEditContext()
|
||||||
{
|
{
|
||||||
var appElement = Browser.MountTestComponent<TypicalValidationComponent>();
|
var appElement = MountTypicalValidationComponent();
|
||||||
var acceptsTermsInput = appElement.FindElement(By.ClassName("accepts-terms")).FindElement(By.TagName("input"));
|
var acceptsTermsInput = appElement.FindElement(By.ClassName("accepts-terms")).FindElement(By.TagName("input"));
|
||||||
var isEvilInput = appElement.FindElement(By.ClassName("is-evil")).FindElement(By.TagName("input"));
|
var isEvilInput = appElement.FindElement(By.ClassName("is-evil")).FindElement(By.TagName("input"));
|
||||||
var messagesAccessor = CreateValidationMessagesAccessor(appElement);
|
var messagesAccessor = CreateValidationMessagesAccessor(appElement);
|
||||||
|
|
@ -297,7 +302,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
|
||||||
var appElement = Browser.MountTestComponent<NotifyPropertyChangedValidationComponent>();
|
var appElement = Browser.MountTestComponent<NotifyPropertyChangedValidationComponent>();
|
||||||
var userNameInput = appElement.FindElement(By.ClassName("user-name")).FindElement(By.TagName("input"));
|
var userNameInput = appElement.FindElement(By.ClassName("user-name")).FindElement(By.TagName("input"));
|
||||||
var acceptsTermsInput = appElement.FindElement(By.ClassName("accepts-terms")).FindElement(By.TagName("input"));
|
var acceptsTermsInput = appElement.FindElement(By.ClassName("accepts-terms")).FindElement(By.TagName("input"));
|
||||||
var submitButton = appElement.FindElement(By.TagName("button"));
|
var submitButton = appElement.FindElement(By.CssSelector("button[type=submit]"));
|
||||||
var messagesAccessor = CreateValidationMessagesAccessor(appElement);
|
var messagesAccessor = CreateValidationMessagesAccessor(appElement);
|
||||||
var submissionStatus = appElement.FindElement(By.Id("submission-status"));
|
var submissionStatus = appElement.FindElement(By.Id("submission-status"));
|
||||||
|
|
||||||
|
|
@ -331,11 +336,11 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
|
||||||
[Fact]
|
[Fact]
|
||||||
public void ValidationMessageDisplaysMessagesForField()
|
public void ValidationMessageDisplaysMessagesForField()
|
||||||
{
|
{
|
||||||
var appElement = Browser.MountTestComponent<TypicalValidationComponent>();
|
var appElement = MountTypicalValidationComponent();
|
||||||
var emailContainer = appElement.FindElement(By.ClassName("email"));
|
var emailContainer = appElement.FindElement(By.ClassName("email"));
|
||||||
var emailInput = emailContainer.FindElement(By.TagName("input"));
|
var emailInput = emailContainer.FindElement(By.TagName("input"));
|
||||||
var emailMessagesAccessor = CreateValidationMessagesAccessor(emailContainer);
|
var emailMessagesAccessor = CreateValidationMessagesAccessor(emailContainer);
|
||||||
var submitButton = appElement.FindElement(By.TagName("button"));
|
var submitButton = appElement.FindElement(By.CssSelector("button[type=submit]"));
|
||||||
|
|
||||||
// Doesn't show messages for other fields
|
// Doesn't show messages for other fields
|
||||||
submitButton.Click();
|
submitButton.Click();
|
||||||
|
|
@ -355,10 +360,43 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
|
||||||
Browser.Empty(emailMessagesAccessor);
|
Browser.Empty(emailMessagesAccessor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ErrorsFromCompareAttribute()
|
||||||
|
{
|
||||||
|
var appElement = MountTypicalValidationComponent();
|
||||||
|
var emailContainer = appElement.FindElement(By.ClassName("email"));
|
||||||
|
var emailInput = emailContainer.FindElement(By.TagName("input"));
|
||||||
|
var confirmEmailContainer = appElement.FindElement(By.ClassName("confirm-email"));
|
||||||
|
var confirmInput = confirmEmailContainer.FindElement(By.TagName("input"));
|
||||||
|
var confirmEmailValidationMessage = CreateValidationMessagesAccessor(confirmEmailContainer);
|
||||||
|
var modelErrors = CreateValidationMessagesAccessor(appElement.FindElement(By.ClassName("model-errors")));
|
||||||
|
CreateValidationMessagesAccessor(emailContainer);
|
||||||
|
var submitButton = appElement.FindElement(By.CssSelector("button[type=submit]"));
|
||||||
|
|
||||||
|
// Updates on edit
|
||||||
|
emailInput.SendKeys("a@b.com\t");
|
||||||
|
|
||||||
|
submitButton.Click();
|
||||||
|
Browser.Empty(confirmEmailValidationMessage);
|
||||||
|
Browser.Equal(new[] { "Email and confirm email do not match." }, modelErrors);
|
||||||
|
|
||||||
|
confirmInput.SendKeys("not-test@example.com\t");
|
||||||
|
Browser.Equal(new[] { "Email and confirm email do not match." }, confirmEmailValidationMessage);
|
||||||
|
|
||||||
|
// Can become correct
|
||||||
|
confirmInput.Clear();
|
||||||
|
confirmInput.SendKeys("a@b.com\t");
|
||||||
|
|
||||||
|
Browser.Empty(confirmEmailValidationMessage);
|
||||||
|
|
||||||
|
submitButton.Click();
|
||||||
|
Browser.Empty(modelErrors);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void InputComponentsCauseContainerToRerenderOnChange()
|
public void InputComponentsCauseContainerToRerenderOnChange()
|
||||||
{
|
{
|
||||||
var appElement = Browser.MountTestComponent<TypicalValidationComponent>();
|
var appElement = MountTypicalValidationComponent();
|
||||||
var ticketClassInput = new SelectElement(appElement.FindElement(By.ClassName("ticket-class")).FindElement(By.TagName("select")));
|
var ticketClassInput = new SelectElement(appElement.FindElement(By.ClassName("ticket-class")).FindElement(By.TagName("select")));
|
||||||
var selectedTicketClassDisplay = appElement.FindElement(By.Id("selected-ticket-class"));
|
var selectedTicketClassDisplay = appElement.FindElement(By.Id("selected-ticket-class"));
|
||||||
var messagesAccessor = CreateValidationMessagesAccessor(appElement);
|
var messagesAccessor = CreateValidationMessagesAccessor(appElement);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,90 @@
|
||||||
|
// 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.FormsTest;
|
||||||
|
using Microsoft.AspNetCore.Components.E2ETest.Infrastructure.ServerFixtures;
|
||||||
|
using Microsoft.AspNetCore.E2ETesting;
|
||||||
|
using OpenQA.Selenium;
|
||||||
|
using OpenQA.Selenium.Support.UI;
|
||||||
|
using Xunit;
|
||||||
|
using Xunit.Abstractions;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Components.E2ETest.Tests
|
||||||
|
{
|
||||||
|
public class FormsTestWithExperimentalValidator : FormsTest
|
||||||
|
{
|
||||||
|
public FormsTestWithExperimentalValidator(
|
||||||
|
BrowserFixture browserFixture,
|
||||||
|
ToggleExecutionModeServerFixture<BasicTestApp.Program> serverFixture,
|
||||||
|
ITestOutputHelper output) : base(browserFixture, serverFixture, output)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override IWebElement MountSimpleValidationComponent()
|
||||||
|
=> Browser.MountTestComponent<SimpleValidationComponentUsingExperimentalValidator>();
|
||||||
|
|
||||||
|
protected override IWebElement MountTypicalValidationComponent()
|
||||||
|
=> Browser.MountTestComponent<TypicalValidationComponentUsingExperimentalValidator>();
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void EditFormWorksWithNestedValidation()
|
||||||
|
{
|
||||||
|
var appElement = Browser.MountTestComponent<ExperimentalValidationComponent>();
|
||||||
|
|
||||||
|
var nameInput = appElement.FindElement(By.CssSelector(".name input"));
|
||||||
|
var emailInput = appElement.FindElement(By.CssSelector(".email input"));
|
||||||
|
var confirmEmailInput = appElement.FindElement(By.CssSelector(".confirm-email input"));
|
||||||
|
var streetInput = appElement.FindElement(By.CssSelector(".street input"));
|
||||||
|
var zipInput = appElement.FindElement(By.CssSelector(".zip input"));
|
||||||
|
var countryInput = new SelectElement(appElement.FindElement(By.CssSelector(".country select")));
|
||||||
|
var descriptionInput = appElement.FindElement(By.CssSelector(".description input"));
|
||||||
|
var weightInput = appElement.FindElement(By.CssSelector(".weight input"));
|
||||||
|
|
||||||
|
var submitButton = appElement.FindElement(By.CssSelector("button[type=submit]"));
|
||||||
|
|
||||||
|
submitButton.Click();
|
||||||
|
|
||||||
|
Browser.Equal(4, () => appElement.FindElements(By.CssSelector(".all-errors .validation-message")).Count);
|
||||||
|
|
||||||
|
Browser.Equal("Enter a name", () => appElement.FindElement(By.CssSelector(".name .validation-message")).Text);
|
||||||
|
Browser.Equal("Enter an email", () => appElement.FindElement(By.CssSelector(".email .validation-message")).Text);
|
||||||
|
Browser.Equal("A street address is required.", () => appElement.FindElement(By.CssSelector(".street .validation-message")).Text);
|
||||||
|
Browser.Equal("Description is required.", () => appElement.FindElement(By.CssSelector(".description .validation-message")).Text);
|
||||||
|
|
||||||
|
// Verify class-level validation
|
||||||
|
nameInput.SendKeys("Some person");
|
||||||
|
emailInput.SendKeys("test@example.com");
|
||||||
|
countryInput.SelectByValue("Mordor");
|
||||||
|
descriptionInput.SendKeys("Fragile staff");
|
||||||
|
streetInput.SendKeys("Mount Doom\t");
|
||||||
|
|
||||||
|
submitButton.Click();
|
||||||
|
|
||||||
|
// Verify member validation from IValidatableObject on a model property, CustomValidationAttribute on a model attribute, and BlazorCompareAttribute.
|
||||||
|
Browser.Equal("A ZipCode is required", () => appElement.FindElement(By.CssSelector(".zip .validation-message")).Text);
|
||||||
|
Browser.Equal("'Confirm email address' and 'EmailAddress' do not match.", () => appElement.FindElement(By.CssSelector(".confirm-email .validation-message")).Text);
|
||||||
|
Browser.Equal("Fragile items must be placed in secure containers", () => appElement.FindElement(By.CssSelector(".item-error .validation-message")).Text);
|
||||||
|
Browser.Equal(3, () => appElement.FindElements(By.CssSelector(".all-errors .validation-message")).Count);
|
||||||
|
|
||||||
|
zipInput.SendKeys("98052");
|
||||||
|
confirmEmailInput.SendKeys("test@example.com");
|
||||||
|
descriptionInput.Clear();
|
||||||
|
weightInput.SendKeys("0");
|
||||||
|
descriptionInput.SendKeys("The One Ring\t");
|
||||||
|
|
||||||
|
submitButton.Click();
|
||||||
|
// Verify validation from IValidatableObject on the model.
|
||||||
|
Browser.Equal("Some items in your list cannot be delivered.", () => appElement.FindElement(By.CssSelector(".model-errors .validation-message")).Text);
|
||||||
|
|
||||||
|
Browser.Single(() => appElement.FindElements(By.CssSelector(".all-errors .validation-message")));
|
||||||
|
|
||||||
|
// Let's make sure the form submits
|
||||||
|
descriptionInput.Clear();
|
||||||
|
descriptionInput.SendKeys("A different ring\t");
|
||||||
|
submitButton.Click();
|
||||||
|
|
||||||
|
Browser.Empty(() => appElement.FindElements(By.CssSelector(".all-errors .validation-message")));
|
||||||
|
Browser.Equal("OnValidSubmit", () => appElement.FindElement(By.CssSelector(".submission-log")).Text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
<Reference Include="Microsoft.AspNetCore.Blazor" />
|
<Reference Include="Microsoft.AspNetCore.Blazor" />
|
||||||
<Reference Include="Microsoft.AspNetCore.Blazor.HttpClient" />
|
<Reference Include="Microsoft.AspNetCore.Blazor.HttpClient" />
|
||||||
<Reference Include="Microsoft.AspNetCore.Components.Authorization" />
|
<Reference Include="Microsoft.AspNetCore.Components.Authorization" />
|
||||||
|
<Reference Include="Microsoft.AspNetCore.Blazor.DataAnnotations.Validation" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,185 @@
|
||||||
|
@using System.ComponentModel.DataAnnotations
|
||||||
|
@using Microsoft.AspNetCore.Components.Forms
|
||||||
|
|
||||||
|
<p>
|
||||||
|
This component is used to verify the use of the experimental ObjectGraphDataAnnotationsValidator type with IValidatableObject and deep validation, as well
|
||||||
|
as the ComparePropertyAttribute.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<EditForm Model="@model" OnValidSubmit="@HandleValidSubmit">
|
||||||
|
<ObjectGraphDataAnnotationsValidator />
|
||||||
|
|
||||||
|
<p class="name">
|
||||||
|
Name: <InputText @bind-Value="model.Recipient" placeholder="Enter the recipient" />
|
||||||
|
<ValidationMessage For="@(() => model.Recipient)" />
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class="email">
|
||||||
|
Email: <InputText @bind-Value="model.EmailAddress" />
|
||||||
|
<ValidationMessage For="@(() => model.EmailAddress)" />
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class="confirm-email">
|
||||||
|
Confirm Email: <InputText @bind-Value="model.ConfirmEmailAddress" />
|
||||||
|
<ValidationMessage For="@(() => model.ConfirmEmailAddress)" />
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<fieldset>
|
||||||
|
<legend>Items to deliver</legend>
|
||||||
|
<p>
|
||||||
|
<button id="addItem" type="button" @onclick="AddItem">Add Item</button>
|
||||||
|
</p>
|
||||||
|
<ul class="items">
|
||||||
|
@foreach (var item in model.Items)
|
||||||
|
{
|
||||||
|
<li>
|
||||||
|
<div style="display: inline-flex; flex-direction: row">
|
||||||
|
<div style="flex-grow: 1" class="description">
|
||||||
|
<InputText @bind-Value="item.Description" placeholder="Description" />
|
||||||
|
<ValidationMessage For="@(() => item.Description)" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style="flex-grow: 1" class="weight">
|
||||||
|
<InputNumber @bind-Value="item.Weight" />
|
||||||
|
<ValidationMessage For="@(() => item.Weight)" />
|
||||||
|
</div>
|
||||||
|
<div style="flex-grow: 1" class="item-error">
|
||||||
|
<ValidationSummary Model="item" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<fieldset>
|
||||||
|
<legend>Shipping details</legend>
|
||||||
|
<p class="street">
|
||||||
|
Street Address: <InputText @bind-Value="model.Address.Street" />
|
||||||
|
<ValidationMessage For="@(() => model.Address.Street)" />
|
||||||
|
</p>
|
||||||
|
<p class="zip">
|
||||||
|
Zip Code: <InputText @bind-Value="model.Address.ZipCode" />
|
||||||
|
<ValidationMessage For="@(() => model.Address.ZipCode)" />
|
||||||
|
</p>
|
||||||
|
<p class="country">
|
||||||
|
Country:
|
||||||
|
<InputSelect @bind-Value="model.Address.Country">
|
||||||
|
<option></option>
|
||||||
|
<option value="@Country.Gondor">@Country.Gondor</option>
|
||||||
|
<option value="@Country.Mordor">@Country.Mordor</option>
|
||||||
|
<option value="@Country.Rohan">@Country.Rohan</option>
|
||||||
|
<option value="@Country.Shire">@Country.Shire</option>
|
||||||
|
</InputSelect>
|
||||||
|
<ValidationMessage For="@(() => model.Address.Country)" />
|
||||||
|
</p>
|
||||||
|
<p class="address-validation">
|
||||||
|
<ValidationSummary Model="model.Address" />
|
||||||
|
</p>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<div class="model-errors">
|
||||||
|
<ValidationSummary Model="model"/>
|
||||||
|
</div>
|
||||||
|
<button type="submit">Submit</button>
|
||||||
|
|
||||||
|
<div class="all-errors">
|
||||||
|
<ValidationSummary />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</EditForm>
|
||||||
|
|
||||||
|
<ul class="submission-log">
|
||||||
|
@foreach (var entry in submissionLog)
|
||||||
|
{
|
||||||
|
<li>@entry</li>
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
Delivery model = new Delivery();
|
||||||
|
|
||||||
|
public class Delivery : IValidatableObject
|
||||||
|
{
|
||||||
|
[Required(ErrorMessage = "Enter a name")]
|
||||||
|
public string Recipient { get; set; }
|
||||||
|
|
||||||
|
[Required(ErrorMessage = "Enter an email")]
|
||||||
|
[EmailAddress(ErrorMessage = "Enter a valid email address")]
|
||||||
|
public string EmailAddress { get; set; }
|
||||||
|
|
||||||
|
[CompareProperty(nameof(EmailAddress))]
|
||||||
|
[Display(Name = "Confirm email address")]
|
||||||
|
public string ConfirmEmailAddress { get; set; }
|
||||||
|
|
||||||
|
[ValidateComplexType]
|
||||||
|
public Address Address { get; } = new Address();
|
||||||
|
|
||||||
|
[ValidateComplexType]
|
||||||
|
public List<Item> Items { get; } = new List<Item>
|
||||||
|
{
|
||||||
|
new Item(),
|
||||||
|
};
|
||||||
|
|
||||||
|
public IEnumerable<ValidationResult> Validate(ValidationContext context)
|
||||||
|
{
|
||||||
|
if (Address.Street == "Mount Doom" && Items.Any(i => i.Description == "The One Ring"))
|
||||||
|
{
|
||||||
|
yield return new ValidationResult("Some items in your list cannot be delivered.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Address : IValidatableObject
|
||||||
|
{
|
||||||
|
[Required(ErrorMessage = "A street address is required.")]
|
||||||
|
public string Street { get; set; }
|
||||||
|
|
||||||
|
public string ZipCode { get; set; }
|
||||||
|
|
||||||
|
[EnumDataType(typeof(Country))]
|
||||||
|
public Country Country { get; set; }
|
||||||
|
|
||||||
|
public IEnumerable<ValidationResult> Validate(ValidationContext context)
|
||||||
|
{
|
||||||
|
if (Country == Country.Mordor && string.IsNullOrEmpty(ZipCode))
|
||||||
|
{
|
||||||
|
yield return new ValidationResult("A ZipCode is required", new[] { nameof(ZipCode) });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[CustomValidation(typeof(Item), nameof(Item.CustomValidate))]
|
||||||
|
public class Item
|
||||||
|
{
|
||||||
|
[Required(ErrorMessage = "Description is required.")]
|
||||||
|
public string Description { get; set; }
|
||||||
|
|
||||||
|
[Range(0.1, 50, ErrorMessage = "Items must weigh between 0.1 and 5")]
|
||||||
|
public double Weight { get; set; } = 1;
|
||||||
|
|
||||||
|
public static ValidationResult CustomValidate(Item item, ValidationContext context)
|
||||||
|
{
|
||||||
|
if (item.Weight < 2.0 && item.Description.StartsWith("Fragile"))
|
||||||
|
{
|
||||||
|
return new ValidationResult("Fragile items must be placed in secure containers");
|
||||||
|
}
|
||||||
|
|
||||||
|
return ValidationResult.Success;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Country { Gondor, Mordor, Rohan, Shire }
|
||||||
|
|
||||||
|
List<string> submissionLog = new List<string>();
|
||||||
|
|
||||||
|
void HandleValidSubmit()
|
||||||
|
{
|
||||||
|
submissionLog.Add("OnValidSubmit");
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddItem()
|
||||||
|
{
|
||||||
|
model.Items.Add(new Item());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,7 +2,14 @@
|
||||||
@using Microsoft.AspNetCore.Components.Forms
|
@using Microsoft.AspNetCore.Components.Forms
|
||||||
|
|
||||||
<EditForm Model="@this" OnValidSubmit="@HandleValidSubmit" OnInvalidSubmit="@HandleInvalidSubmit" autocomplete="off">
|
<EditForm Model="@this" OnValidSubmit="@HandleValidSubmit" OnInvalidSubmit="@HandleInvalidSubmit" autocomplete="off">
|
||||||
|
@if (UseExperimentalValidator)
|
||||||
|
{
|
||||||
|
<ObjectGraphDataAnnotationsValidator />
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
<DataAnnotationsValidator />
|
<DataAnnotationsValidator />
|
||||||
|
}
|
||||||
|
|
||||||
<p class="user-name">
|
<p class="user-name">
|
||||||
User name: <input @bind="UserName" class="@context.FieldCssClass(() => UserName)" />
|
User name: <input @bind="UserName" class="@context.FieldCssClass(() => UserName)" />
|
||||||
|
|
@ -29,6 +36,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
|
protected virtual bool UseExperimentalValidator => false;
|
||||||
|
|
||||||
string lastCallback;
|
string lastCallback;
|
||||||
|
|
||||||
[Required(ErrorMessage = "Please choose a username")]
|
[Required(ErrorMessage = "Please choose a username")]
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
namespace BasicTestApp.FormsTest
|
||||||
|
{
|
||||||
|
public class TypicalValidationComponentUsingExperimentalValidator : TypicalValidationComponent
|
||||||
|
{
|
||||||
|
protected override bool UseExperimentalValidator => true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,7 +2,14 @@
|
||||||
@using Microsoft.AspNetCore.Components.Forms
|
@using Microsoft.AspNetCore.Components.Forms
|
||||||
|
|
||||||
<EditForm EditContext="@editContext" OnValidSubmit="@HandleValidSubmit">
|
<EditForm EditContext="@editContext" OnValidSubmit="@HandleValidSubmit">
|
||||||
|
@if (UseExperimentalValidator)
|
||||||
|
{
|
||||||
|
<ObjectGraphDataAnnotationsValidator />
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
<DataAnnotationsValidator />
|
<DataAnnotationsValidator />
|
||||||
|
}
|
||||||
|
|
||||||
<p class="name">
|
<p class="name">
|
||||||
Name: <InputText @bind-Value="person.Name" placeholder="Enter your name" />
|
Name: <InputText @bind-Value="person.Name" placeholder="Enter your name" />
|
||||||
|
|
@ -11,6 +18,10 @@
|
||||||
Email: <InputText @bind-Value="person.Email" />
|
Email: <InputText @bind-Value="person.Email" />
|
||||||
<ValidationMessage For="@(() => person.Email)" />
|
<ValidationMessage For="@(() => person.Email)" />
|
||||||
</p>
|
</p>
|
||||||
|
<p class="confirm-email">
|
||||||
|
Email: <InputText @bind-Value="person.ConfirmEmail" />
|
||||||
|
<ValidationMessage For="@(() => person.ConfirmEmail)" />
|
||||||
|
</p>
|
||||||
<p class="age">
|
<p class="age">
|
||||||
Age (years): <InputNumber @bind-Value="person.AgeInYears" placeholder="Enter your age" />
|
Age (years): <InputNumber @bind-Value="person.AgeInYears" placeholder="Enter your age" />
|
||||||
</p>
|
</p>
|
||||||
|
|
@ -49,12 +60,18 @@
|
||||||
|
|
||||||
<button type="submit">Submit</button>
|
<button type="submit">Submit</button>
|
||||||
|
|
||||||
|
<p class="model-errors">
|
||||||
|
<ValidationSummary Model="person" />
|
||||||
|
</p>
|
||||||
|
|
||||||
<ValidationSummary />
|
<ValidationSummary />
|
||||||
</EditForm>
|
</EditForm>
|
||||||
|
|
||||||
<ul>@foreach (var entry in submissionLog) { <li>@entry</li> }</ul>
|
<ul>@foreach (var entry in submissionLog) { <li>@entry</li> }</ul>
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
|
protected virtual bool UseExperimentalValidator => false;
|
||||||
|
|
||||||
Person person = new Person();
|
Person person = new Person();
|
||||||
EditContext editContext;
|
EditContext editContext;
|
||||||
ValidationMessageStore customValidationMessageStore;
|
ValidationMessageStore customValidationMessageStore;
|
||||||
|
|
@ -75,6 +92,9 @@
|
||||||
[StringLength(10, ErrorMessage = "We only accept very short email addresses (max 10 chars)")]
|
[StringLength(10, ErrorMessage = "We only accept very short email addresses (max 10 chars)")]
|
||||||
public string Email { get; set; }
|
public string Email { get; set; }
|
||||||
|
|
||||||
|
[Compare(nameof(Email), ErrorMessage = "Email and confirm email do not match.")]
|
||||||
|
public string ConfirmEmail { get; set; }
|
||||||
|
|
||||||
[Range(0, 200, ErrorMessage = "Nobody is that old")]
|
[Range(0, 200, ErrorMessage = "Nobody is that old")]
|
||||||
public int AgeInYears { get; set; }
|
public int AgeInYears { get; set; }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
namespace BasicTestApp.FormsTest
|
||||||
|
{
|
||||||
|
public class SimpleValidationComponentUsingExperimentalValidator : SimpleValidationComponent
|
||||||
|
{
|
||||||
|
protected override bool UseExperimentalValidator => true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -29,7 +29,10 @@
|
||||||
<option value="BasicTestApp.FocusEventComponent">Focus events</option>
|
<option value="BasicTestApp.FocusEventComponent">Focus events</option>
|
||||||
<option value="BasicTestApp.FormsTest.NotifyPropertyChangedValidationComponent">INotifyPropertyChanged validation</option>
|
<option value="BasicTestApp.FormsTest.NotifyPropertyChangedValidationComponent">INotifyPropertyChanged validation</option>
|
||||||
<option value="BasicTestApp.FormsTest.SimpleValidationComponent">Simple validation</option>
|
<option value="BasicTestApp.FormsTest.SimpleValidationComponent">Simple validation</option>
|
||||||
|
<option value="BasicTestApp.FormsTest.SimpleValidationComponentUsingExperimentalValidator">Simple validation using experimental validator</option>
|
||||||
<option value="BasicTestApp.FormsTest.TypicalValidationComponent">Typical validation</option>
|
<option value="BasicTestApp.FormsTest.TypicalValidationComponent">Typical validation</option>
|
||||||
|
<option value="BasicTestApp.FormsTest.TypicalValidationComponentUsingExperimentalValidator">Typical validation using experimental validator</option>
|
||||||
|
<option value="BasicTestApp.FormsTest.ExperimentalValidationComponent">Experimental validation</option>
|
||||||
<option value="BasicTestApp.GlobalizationBindCases">Globalization Bind Cases</option>
|
<option value="BasicTestApp.GlobalizationBindCases">Globalization Bind Cases</option>
|
||||||
<option value="BasicTestApp.HierarchicalImportsTest.Subdir.ComponentUsingImports">Imports statement</option>
|
<option value="BasicTestApp.HierarchicalImportsTest.Subdir.ComponentUsingImports">Imports statement</option>
|
||||||
<option value="BasicTestApp.HtmlBlockChildContent">ChildContent HTML Block</option>
|
<option value="BasicTestApp.HtmlBlockChildContent">ChildContent HTML Block</option>
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,16 @@ html, body {
|
||||||
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
a, .btn-link {
|
||||||
|
color: #0366d6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary {
|
||||||
|
color: #fff;
|
||||||
|
background-color: #1b6ec2;
|
||||||
|
border-color: #1861ac;
|
||||||
|
}
|
||||||
|
|
||||||
app {
|
app {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
@ -21,8 +31,19 @@ app {
|
||||||
}
|
}
|
||||||
|
|
||||||
.main .top-row {
|
.main .top-row {
|
||||||
background-color: #e6e6e6;
|
background-color: #f7f7f7;
|
||||||
border-bottom: 1px solid #d6d5d5;
|
border-bottom: 1px solid #d6d5d5;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main .top-row > a, .main .top-row .btn-link {
|
||||||
|
white-space: nowrap;
|
||||||
|
margin-left: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main .top-row a:first-child {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar {
|
.sidebar {
|
||||||
|
|
@ -44,20 +65,20 @@ app {
|
||||||
top: -2px;
|
top: -2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-item {
|
.sidebar .nav-item {
|
||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
padding-bottom: 0.5rem;
|
padding-bottom: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-item:first-of-type {
|
.sidebar .nav-item:first-of-type {
|
||||||
padding-top: 1rem;
|
padding-top: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-item:last-of-type {
|
.sidebar .nav-item:last-of-type {
|
||||||
padding-bottom: 1rem;
|
padding-bottom: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-item a {
|
.sidebar .nav-item a {
|
||||||
color: #d7d7d7;
|
color: #d7d7d7;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
height: 3rem;
|
height: 3rem;
|
||||||
|
|
@ -66,12 +87,12 @@ app {
|
||||||
line-height: 3rem;
|
line-height: 3rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-item a.active {
|
.sidebar .nav-item a.active {
|
||||||
background-color: rgba(255,255,255,0.25);
|
background-color: rgba(255,255,255,0.25);
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-item a:hover {
|
.sidebar .nav-item a:hover {
|
||||||
background-color: rgba(255,255,255,0.1);
|
background-color: rgba(255,255,255,0.1);
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
@ -96,9 +117,36 @@ app {
|
||||||
color: red;
|
color: red;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 767.98px) {
|
#blazor-error-ui {
|
||||||
.main .top-row {
|
background: lightyellow;
|
||||||
|
bottom: 0;
|
||||||
|
box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
|
||||||
display: none;
|
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:not(.auth) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main .top-row.auth {
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main .top-row a, .main .top-row .btn-link {
|
||||||
|
margin-left: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,17 +24,15 @@ namespace Microsoft.AspNetCore.Hosting.FunctionalTests
|
||||||
|
|
||||||
public ShutdownTests(ITestOutputHelper output) : base(output) { }
|
public ShutdownTests(ITestOutputHelper output) : base(output) { }
|
||||||
|
|
||||||
[ConditionalFact(Skip = "https://github.com/aspnet/AspNetCore-Internal/issues/2577")]
|
[ConditionalFact]
|
||||||
[OSSkipCondition(OperatingSystems.Windows)]
|
[OSSkipCondition(OperatingSystems.Windows)]
|
||||||
[OSSkipCondition(OperatingSystems.MacOSX)]
|
[OSSkipCondition(OperatingSystems.MacOSX)]
|
||||||
[Flaky("https://github.com/aspnet/AspNetCore-Internal/issues/2577", FlakyOn.All)]
|
|
||||||
public async Task ShutdownTestRun()
|
public async Task ShutdownTestRun()
|
||||||
{
|
{
|
||||||
await ExecuteShutdownTest(nameof(ShutdownTestRun), "Run");
|
await ExecuteShutdownTest(nameof(ShutdownTestRun), "Run");
|
||||||
}
|
}
|
||||||
|
|
||||||
[ConditionalFact]
|
[ConditionalFact]
|
||||||
[Flaky("https://github.com/aspnet/Hosting/issues/1214", FlakyOn.All)]
|
|
||||||
[OSSkipCondition(OperatingSystems.Windows)]
|
[OSSkipCondition(OperatingSystems.Windows)]
|
||||||
[OSSkipCondition(OperatingSystems.MacOSX)]
|
[OSSkipCondition(OperatingSystems.MacOSX)]
|
||||||
public async Task ShutdownTestWaitForShutdown()
|
public async Task ShutdownTestWaitForShutdown()
|
||||||
|
|
|
||||||
|
|
@ -167,7 +167,7 @@ namespace Microsoft.AspNetCore.WebUtilities
|
||||||
if (!isFinalBlock)
|
if (!isFinalBlock)
|
||||||
{
|
{
|
||||||
// Don't buffer indefinately
|
// Don't buffer indefinately
|
||||||
if (span.Length > KeyLengthLimit + ValueLengthLimit)
|
if ((uint)span.Length > (uint)KeyLengthLimit + (uint)ValueLengthLimit)
|
||||||
{
|
{
|
||||||
ThrowKeyOrValueTooLargeException();
|
ThrowKeyOrValueTooLargeException();
|
||||||
}
|
}
|
||||||
|
|
@ -236,7 +236,7 @@ namespace Microsoft.AspNetCore.WebUtilities
|
||||||
if (!isFinalBlock)
|
if (!isFinalBlock)
|
||||||
{
|
{
|
||||||
// Don't buffer indefinately
|
// Don't buffer indefinately
|
||||||
if ((sequenceReader.Consumed - consumedBytes) > KeyLengthLimit + ValueLengthLimit)
|
if ((uint)(sequenceReader.Consumed - consumedBytes) > (uint)KeyLengthLimit + (uint)ValueLengthLimit)
|
||||||
{
|
{
|
||||||
ThrowKeyOrValueTooLargeException();
|
ThrowKeyOrValueTooLargeException();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -211,6 +211,28 @@ namespace Microsoft.AspNetCore.WebUtilities
|
||||||
Assert.Equal("", dict["t"]);
|
Assert.Equal("", dict["t"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[MemberData(nameof(Encodings))]
|
||||||
|
public void TryParseFormValues_LimitsCanBeLarge(Encoding encoding)
|
||||||
|
{
|
||||||
|
var readOnlySequence = ReadOnlySequenceFactory.SingleSegmentFactory.CreateWithContent(encoding.GetBytes("foo=bar&baz=boo&t="));
|
||||||
|
|
||||||
|
KeyValueAccumulator accumulator = default;
|
||||||
|
|
||||||
|
var formReader = new FormPipeReader(null, encoding);
|
||||||
|
formReader.KeyLengthLimit = int.MaxValue;
|
||||||
|
formReader.ValueLengthLimit = int.MaxValue;
|
||||||
|
formReader.ParseFormValues(ref readOnlySequence, ref accumulator, isFinalBlock: false);
|
||||||
|
formReader.ParseFormValues(ref readOnlySequence, ref accumulator, isFinalBlock: true);
|
||||||
|
Assert.True(readOnlySequence.IsEmpty);
|
||||||
|
|
||||||
|
Assert.Equal(3, accumulator.KeyCount);
|
||||||
|
var dict = accumulator.GetResults();
|
||||||
|
Assert.Equal("bar", dict["foo"]);
|
||||||
|
Assert.Equal("boo", dict["baz"]);
|
||||||
|
Assert.Equal("", dict["t"]);
|
||||||
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[MemberData(nameof(Encodings))]
|
[MemberData(nameof(Encodings))]
|
||||||
public void TryParseFormValues_SplitAcrossSegmentsWorks(Encoding encoding)
|
public void TryParseFormValues_SplitAcrossSegmentsWorks(Encoding encoding)
|
||||||
|
|
@ -230,6 +252,28 @@ namespace Microsoft.AspNetCore.WebUtilities
|
||||||
Assert.Equal("", dict["t"]);
|
Assert.Equal("", dict["t"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[MemberData(nameof(Encodings))]
|
||||||
|
public void TryParseFormValues_SplitAcrossSegmentsWorks_LimitsCanBeLarge(Encoding encoding)
|
||||||
|
{
|
||||||
|
var readOnlySequence = ReadOnlySequenceFactory.SegmentPerByteFactory.CreateWithContent(encoding.GetBytes("foo=bar&baz=boo&t="));
|
||||||
|
|
||||||
|
KeyValueAccumulator accumulator = default;
|
||||||
|
|
||||||
|
var formReader = new FormPipeReader(null, encoding);
|
||||||
|
formReader.KeyLengthLimit = int.MaxValue;
|
||||||
|
formReader.ValueLengthLimit = int.MaxValue;
|
||||||
|
formReader.ParseFormValues(ref readOnlySequence, ref accumulator, isFinalBlock: false);
|
||||||
|
formReader.ParseFormValues(ref readOnlySequence, ref accumulator, isFinalBlock: true);
|
||||||
|
Assert.True(readOnlySequence.IsEmpty);
|
||||||
|
|
||||||
|
Assert.Equal(3, accumulator.KeyCount);
|
||||||
|
var dict = accumulator.GetResults();
|
||||||
|
Assert.Equal("bar", dict["foo"]);
|
||||||
|
Assert.Equal("boo", dict["baz"]);
|
||||||
|
Assert.Equal("", dict["t"]);
|
||||||
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[MemberData(nameof(Encodings))]
|
[MemberData(nameof(Encodings))]
|
||||||
public void TryParseFormValues_MultiSegmentWithArrayPoolAcrossSegmentsWorks(Encoding encoding)
|
public void TryParseFormValues_MultiSegmentWithArrayPoolAcrossSegmentsWorks(Encoding encoding)
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ namespace Microsoft.AspNetCore.Identity
|
||||||
{
|
{
|
||||||
var key = await manager.GetAuthenticatorKeyAsync(user);
|
var key = await manager.GetAuthenticatorKeyAsync(user);
|
||||||
int code;
|
int code;
|
||||||
if (!int.TryParse(token, out code))
|
if (key == null || !int.TryParse(token, out code))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -108,7 +108,6 @@ namespace Microsoft.AspNetCore.Identity.UI.V3.Pages.Account.Internal
|
||||||
public string ReturnUrl { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
public string ReturnUrl { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||||
public virtual System.Threading.Tasks.Task OnGetAsync(string returnUrl = null) { throw null; }
|
public virtual System.Threading.Tasks.Task OnGetAsync(string returnUrl = null) { throw null; }
|
||||||
public virtual System.Threading.Tasks.Task<Microsoft.AspNetCore.Mvc.IActionResult> OnPostAsync(string returnUrl = null) { throw null; }
|
public virtual System.Threading.Tasks.Task<Microsoft.AspNetCore.Mvc.IActionResult> OnPostAsync(string returnUrl = null) { throw null; }
|
||||||
public virtual System.Threading.Tasks.Task<Microsoft.AspNetCore.Mvc.IActionResult> OnPostSendVerificationEmailAsync() { throw null; }
|
|
||||||
public partial class InputModel
|
public partial class InputModel
|
||||||
{
|
{
|
||||||
public InputModel() { }
|
public InputModel() { }
|
||||||
|
|
@ -177,7 +176,7 @@ namespace Microsoft.AspNetCore.Identity.UI.V3.Pages.Account.Internal
|
||||||
public bool DisplayConfirmAccountLink { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
public bool DisplayConfirmAccountLink { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||||
public string Email { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
public string Email { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||||
public string EmailConfirmationUrl { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
public string EmailConfirmationUrl { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||||
public virtual System.Threading.Tasks.Task<Microsoft.AspNetCore.Mvc.IActionResult> OnGetAsync(string email) { throw null; }
|
public virtual System.Threading.Tasks.Task<Microsoft.AspNetCore.Mvc.IActionResult> OnGetAsync(string email, string returnUrl = null) { throw null; }
|
||||||
}
|
}
|
||||||
[Microsoft.AspNetCore.Authorization.AllowAnonymousAttribute]
|
[Microsoft.AspNetCore.Authorization.AllowAnonymousAttribute]
|
||||||
public abstract partial class RegisterModel : Microsoft.AspNetCore.Mvc.RazorPages.PageModel
|
public abstract partial class RegisterModel : Microsoft.AspNetCore.Mvc.RazorPages.PageModel
|
||||||
|
|
@ -627,7 +626,7 @@ namespace Microsoft.AspNetCore.Identity.UI.V4.Pages.Account.Internal
|
||||||
public bool DisplayConfirmAccountLink { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
public bool DisplayConfirmAccountLink { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||||
public string Email { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
public string Email { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||||
public string EmailConfirmationUrl { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
public string EmailConfirmationUrl { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||||
public virtual System.Threading.Tasks.Task<Microsoft.AspNetCore.Mvc.IActionResult> OnGetAsync(string email) { throw null; }
|
public virtual System.Threading.Tasks.Task<Microsoft.AspNetCore.Mvc.IActionResult> OnGetAsync(string email, string returnUrl = null) { throw null; }
|
||||||
}
|
}
|
||||||
[Microsoft.AspNetCore.Authorization.AllowAnonymousAttribute]
|
[Microsoft.AspNetCore.Authorization.AllowAnonymousAttribute]
|
||||||
public abstract partial class RegisterModel : Microsoft.AspNetCore.Mvc.RazorPages.PageModel
|
public abstract partial class RegisterModel : Microsoft.AspNetCore.Mvc.RazorPages.PageModel
|
||||||
|
|
|
||||||
|
|
@ -41,9 +41,6 @@
|
||||||
<p>
|
<p>
|
||||||
<a asp-page="./Register" asp-route-returnUrl="@Model.ReturnUrl">Register as a new user</a>
|
<a asp-page="./Register" asp-route-returnUrl="@Model.ReturnUrl">Register as a new user</a>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
|
||||||
<button id="resend-confirmation" type="submit" asp-page-handler="SendVerificationEmail" class="btn-link" style="padding:0px;margin:0px;border:0px">Resend email confirmation</button>
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</section>
|
</section>
|
||||||
|
|
|
||||||
|
|
@ -92,12 +92,6 @@ namespace Microsoft.AspNetCore.Identity.UI.V3.Pages.Account.Internal
|
||||||
/// directly from your code. This API may change or be removed in future releases.
|
/// directly from your code. This API may change or be removed in future releases.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual Task<IActionResult> OnPostAsync(string returnUrl = null) => throw new NotImplementedException();
|
public virtual Task<IActionResult> OnPostAsync(string returnUrl = null) => throw new NotImplementedException();
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
|
||||||
/// directly from your code. This API may change or be removed in future releases.
|
|
||||||
/// </summary>
|
|
||||||
public virtual Task<IActionResult> OnPostSendVerificationEmailAsync() => throw new NotImplementedException();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class LoginModel<TUser> : LoginModel where TUser : class
|
internal class LoginModel<TUser> : LoginModel where TUser : class
|
||||||
|
|
@ -105,15 +99,12 @@ namespace Microsoft.AspNetCore.Identity.UI.V3.Pages.Account.Internal
|
||||||
private readonly UserManager<TUser> _userManager;
|
private readonly UserManager<TUser> _userManager;
|
||||||
private readonly SignInManager<TUser> _signInManager;
|
private readonly SignInManager<TUser> _signInManager;
|
||||||
private readonly ILogger<LoginModel> _logger;
|
private readonly ILogger<LoginModel> _logger;
|
||||||
private readonly IEmailSender _emailSender;
|
|
||||||
|
|
||||||
public LoginModel(SignInManager<TUser> signInManager, ILogger<LoginModel> logger,
|
public LoginModel(SignInManager<TUser> signInManager, ILogger<LoginModel> logger,
|
||||||
UserManager<TUser> userManager,
|
UserManager<TUser> userManager)
|
||||||
IEmailSender emailSender)
|
|
||||||
{
|
{
|
||||||
_userManager = userManager;
|
_userManager = userManager;
|
||||||
_signInManager = signInManager;
|
_signInManager = signInManager;
|
||||||
_emailSender = emailSender;
|
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -169,34 +160,5 @@ namespace Microsoft.AspNetCore.Identity.UI.V3.Pages.Account.Internal
|
||||||
// If we got this far, something failed, redisplay form
|
// If we got this far, something failed, redisplay form
|
||||||
return Page();
|
return Page();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task<IActionResult> OnPostSendVerificationEmailAsync()
|
|
||||||
{
|
|
||||||
if (!ModelState.IsValid)
|
|
||||||
{
|
|
||||||
return Page();
|
|
||||||
}
|
|
||||||
|
|
||||||
var user = await _userManager.FindByEmailAsync(Input.Email);
|
|
||||||
if (user == null)
|
|
||||||
{
|
|
||||||
ModelState.AddModelError(string.Empty, "Verification email sent. Please check your email.");
|
|
||||||
}
|
|
||||||
|
|
||||||
var userId = await _userManager.GetUserIdAsync(user);
|
|
||||||
var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
|
|
||||||
var callbackUrl = Url.Page(
|
|
||||||
"/Account/ConfirmEmail",
|
|
||||||
pageHandler: null,
|
|
||||||
values: new { userId = userId, code = code },
|
|
||||||
protocol: Request.Scheme);
|
|
||||||
await _emailSender.SendEmailAsync(
|
|
||||||
Input.Email,
|
|
||||||
"Confirm your email",
|
|
||||||
$"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");
|
|
||||||
|
|
||||||
ModelState.AddModelError(string.Empty, "Verification email sent. Please check your email.");
|
|
||||||
return Page();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -147,7 +147,7 @@ namespace Microsoft.AspNetCore.Identity.UI.V3.Pages.Account.Internal
|
||||||
var callbackUrl = Url.Page(
|
var callbackUrl = Url.Page(
|
||||||
"/Account/ConfirmEmail",
|
"/Account/ConfirmEmail",
|
||||||
pageHandler: null,
|
pageHandler: null,
|
||||||
values: new { area = "Identity", userId = userId, code = code },
|
values: new { area = "Identity", userId = userId, code = code, returnUrl = returnUrl },
|
||||||
protocol: Request.Scheme);
|
protocol: Request.Scheme);
|
||||||
|
|
||||||
await _emailSender.SendEmailAsync(Input.Email, "Confirm your email",
|
await _emailSender.SendEmailAsync(Input.Email, "Confirm your email",
|
||||||
|
|
@ -155,7 +155,7 @@ namespace Microsoft.AspNetCore.Identity.UI.V3.Pages.Account.Internal
|
||||||
|
|
||||||
if (_userManager.Options.SignIn.RequireConfirmedAccount)
|
if (_userManager.Options.SignIn.RequireConfirmedAccount)
|
||||||
{
|
{
|
||||||
return RedirectToPage("RegisterConfirmation", new { email = Input.Email });
|
return RedirectToPage("RegisterConfirmation", new { email = Input.Email, returnUrl = returnUrl });
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ namespace Microsoft.AspNetCore.Identity.UI.V3.Pages.Account.Internal
|
||||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||||
/// directly from your code. This API may change or be removed in future releases.
|
/// directly from your code. This API may change or be removed in future releases.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual Task<IActionResult> OnGetAsync(string email) => throw new NotImplementedException();
|
public virtual Task<IActionResult> OnGetAsync(string email, string returnUrl = null) => throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class RegisterConfirmationModel<TUser> : RegisterConfirmationModel where TUser : class
|
internal class RegisterConfirmationModel<TUser> : RegisterConfirmationModel where TUser : class
|
||||||
|
|
@ -57,12 +57,13 @@ namespace Microsoft.AspNetCore.Identity.UI.V3.Pages.Account.Internal
|
||||||
_sender = sender;
|
_sender = sender;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task<IActionResult> OnGetAsync(string email)
|
public override async Task<IActionResult> OnGetAsync(string email, string returnUrl = null)
|
||||||
{
|
{
|
||||||
if (email == null)
|
if (email == null)
|
||||||
{
|
{
|
||||||
return RedirectToPage("/Index");
|
return RedirectToPage("/Index");
|
||||||
}
|
}
|
||||||
|
returnUrl = returnUrl ?? Url.Content("~/");
|
||||||
|
|
||||||
var user = await _userManager.FindByEmailAsync(email);
|
var user = await _userManager.FindByEmailAsync(email);
|
||||||
if (user == null)
|
if (user == null)
|
||||||
|
|
@ -81,7 +82,7 @@ namespace Microsoft.AspNetCore.Identity.UI.V3.Pages.Account.Internal
|
||||||
EmailConfirmationUrl = Url.Page(
|
EmailConfirmationUrl = Url.Page(
|
||||||
"/Account/ConfirmEmail",
|
"/Account/ConfirmEmail",
|
||||||
pageHandler: null,
|
pageHandler: null,
|
||||||
values: new { area = "Identity", userId = userId, code = code },
|
values: new { area = "Identity", userId = userId, code = code, returnUrl = returnUrl },
|
||||||
protocol: Request.Scheme);
|
protocol: Request.Scheme);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -146,7 +146,7 @@ namespace Microsoft.AspNetCore.Identity.UI.V4.Pages.Account.Internal
|
||||||
var callbackUrl = Url.Page(
|
var callbackUrl = Url.Page(
|
||||||
"/Account/ConfirmEmail",
|
"/Account/ConfirmEmail",
|
||||||
pageHandler: null,
|
pageHandler: null,
|
||||||
values: new { area = "Identity", userId = userId, code = code },
|
values: new { area = "Identity", userId = userId, code = code, returnUrl = returnUrl },
|
||||||
protocol: Request.Scheme);
|
protocol: Request.Scheme);
|
||||||
|
|
||||||
await _emailSender.SendEmailAsync(Input.Email, "Confirm your email",
|
await _emailSender.SendEmailAsync(Input.Email, "Confirm your email",
|
||||||
|
|
@ -154,7 +154,7 @@ namespace Microsoft.AspNetCore.Identity.UI.V4.Pages.Account.Internal
|
||||||
|
|
||||||
if (_userManager.Options.SignIn.RequireConfirmedAccount)
|
if (_userManager.Options.SignIn.RequireConfirmedAccount)
|
||||||
{
|
{
|
||||||
return RedirectToPage("RegisterConfirmation", new { email = Input.Email });
|
return RedirectToPage("RegisterConfirmation", new { email = Input.Email, returnUrl = returnUrl });
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ namespace Microsoft.AspNetCore.Identity.UI.V4.Pages.Account.Internal
|
||||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||||
/// directly from your code. This API may change or be removed in future releases.
|
/// directly from your code. This API may change or be removed in future releases.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual Task<IActionResult> OnGetAsync(string email) => throw new NotImplementedException();
|
public virtual Task<IActionResult> OnGetAsync(string email, string returnUrl = null) => throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class RegisterConfirmationModel<TUser> : RegisterConfirmationModel where TUser : class
|
internal class RegisterConfirmationModel<TUser> : RegisterConfirmationModel where TUser : class
|
||||||
|
|
@ -57,12 +57,13 @@ namespace Microsoft.AspNetCore.Identity.UI.V4.Pages.Account.Internal
|
||||||
_sender = sender;
|
_sender = sender;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task<IActionResult> OnGetAsync(string email)
|
public override async Task<IActionResult> OnGetAsync(string email, string returnUrl = null)
|
||||||
{
|
{
|
||||||
if (email == null)
|
if (email == null)
|
||||||
{
|
{
|
||||||
return RedirectToPage("/Index");
|
return RedirectToPage("/Index");
|
||||||
}
|
}
|
||||||
|
returnUrl = returnUrl ?? Url.Content("~/");
|
||||||
|
|
||||||
var user = await _userManager.FindByEmailAsync(email);
|
var user = await _userManager.FindByEmailAsync(email);
|
||||||
if (user == null)
|
if (user == null)
|
||||||
|
|
@ -81,7 +82,7 @@ namespace Microsoft.AspNetCore.Identity.UI.V4.Pages.Account.Internal
|
||||||
EmailConfirmationUrl = Url.Page(
|
EmailConfirmationUrl = Url.Page(
|
||||||
"/Account/ConfirmEmail",
|
"/Account/ConfirmEmail",
|
||||||
pageHandler: null,
|
pageHandler: null,
|
||||||
values: new { area = "Identity", userId = userId, code = code },
|
values: new { area = "Identity", userId = userId, code = code, returnUrl = returnUrl },
|
||||||
protocol: Request.Scheme);
|
protocol: Request.Scheme);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -56,12 +56,13 @@
|
||||||
</div>
|
</div>
|
||||||
<footer class="footer border-top pl-3 text-muted">
|
<footer class="footer border-top pl-3 text-muted">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
© @DateTime.Now.Year - @Environment.ApplicationName -
|
© @DateTime.Now.Year - @Environment.ApplicationName
|
||||||
@{
|
@{
|
||||||
var foundPrivacy = Url.Page("/Privacy", new { area = "" });
|
var foundPrivacy = Url.Page("/Privacy", new { area = "" });
|
||||||
}
|
}
|
||||||
@if (foundPrivacy != null)
|
@if (foundPrivacy != null)
|
||||||
{
|
{
|
||||||
|
@:-
|
||||||
<a asp-area="" asp-page="/Privacy">Privacy</a>
|
<a asp-area="" asp-page="/Privacy">Privacy</a>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,7 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests.Account
|
||||||
});
|
});
|
||||||
|
|
||||||
var registeredLocation = ResponseAssert.IsRedirect(registered);
|
var registeredLocation = ResponseAssert.IsRedirect(registered);
|
||||||
Assert.Equal(RegisterConfirmation.Path + "?email="+userName, registeredLocation.ToString());
|
Assert.Equal(RegisterConfirmation.Path + "?email="+userName+"&returnUrl=%2F", registeredLocation.ToString());
|
||||||
var registerResponse = await Client.GetAsync(registeredLocation);
|
var registerResponse = await Client.GetAsync(registeredLocation);
|
||||||
var register = await ResponseAssert.IsHtmlDocumentAsync(registerResponse);
|
var register = await ResponseAssert.IsHtmlDocumentAsync(registerResponse);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,8 @@
|
||||||
<Target Name="Build" DependsOnTargets="DebBuild" />
|
<Target Name="Build" DependsOnTargets="DebBuild" />
|
||||||
<Target Name="Pack" />
|
<Target Name="Pack" />
|
||||||
|
|
||||||
<Target Name="DebBuild" DependsOnTargets="$(DebBuildDependsOn)" Condition="'$(IsTargetingPackBuilding)' != 'false'">
|
<Target Name="DebBuild" DependsOnTargets="$(DebBuildDependsOn)"
|
||||||
|
Condition="!( '$(IsTargetingPackBuilding)' == 'false' AND '$(MSBuildProjectName)' == 'Debian.TargetingPack' )">
|
||||||
<!-- Generate debian_config.json. We can't simply use WriteLinesToFile because of https://github.com/Microsoft/msbuild/issues/1622. Use our custom GenerateFileFromTemplate task instead -->
|
<!-- Generate debian_config.json. We can't simply use WriteLinesToFile because of https://github.com/Microsoft/msbuild/issues/1622. Use our custom GenerateFileFromTemplate task instead -->
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<DebianConfigProperties>
|
<DebianConfigProperties>
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,8 @@
|
||||||
<Target Name="Build" DependsOnTargets="RpmBuild" />
|
<Target Name="Build" DependsOnTargets="RpmBuild" />
|
||||||
<Target Name="Pack" />
|
<Target Name="Pack" />
|
||||||
|
|
||||||
<Target Name="RpmBuild" DependsOnTargets="$(RpmBuildDependsOn)" Condition="'$(IsTargetingPackBuilding)' != 'false'">
|
<Target Name="RpmBuild" DependsOnTargets="$(RpmBuildDependsOn)"
|
||||||
|
Condition="!( '$(IsTargetingPackBuilding)' == 'false' AND '$(MSBuildProjectName)' == 'Rpm.TargetingPack' )">
|
||||||
<!-- Create layout: Create changelog -->
|
<!-- Create layout: Create changelog -->
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<ChangeLogProps>DATE=$([System.DateTime]::UtcNow.ToString(ddd MMM dd yyyy))</ChangeLogProps>
|
<ChangeLogProps>DATE=$([System.DateTime]::UtcNow.ToString(ddd MMM dd yyyy))</ChangeLogProps>
|
||||||
|
|
|
||||||
|
|
@ -82,7 +82,8 @@
|
||||||
<BuildDependsOn Condition="'$(IsTargetingPackBuilding)' == 'false'" />
|
<BuildDependsOn Condition="'$(IsTargetingPackBuilding)' == 'false'" />
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<Target Name="CreateTargetingPackNugetPackage" AfterTargets="CopyToArtifactsDirectory;Build">
|
<Target Name="CreateTargetingPackNugetPackage" AfterTargets="CopyToArtifactsDirectory;Build"
|
||||||
|
Condition="'$(IsTargetingPackBuilding)' != 'false'">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<MsiFullPath>$(InstallersOutputPath)$(PackageFileName)</MsiFullPath>
|
<MsiFullPath>$(InstallersOutputPath)$(PackageFileName)</MsiFullPath>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -882,11 +882,14 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
||||||
public Microsoft.AspNetCore.Mvc.ModelBinding.Metadata.ModelMetadataKind MetadataKind { get { throw null; } }
|
public Microsoft.AspNetCore.Mvc.ModelBinding.Metadata.ModelMetadataKind MetadataKind { get { throw null; } }
|
||||||
public System.Type ModelType { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
|
public System.Type ModelType { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
|
||||||
public string Name { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
|
public string Name { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
|
||||||
public System.Reflection.ParameterInfo ParameterInfo { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
|
public System.Reflection.ParameterInfo ParameterInfo { get { throw null; } }
|
||||||
|
public System.Reflection.PropertyInfo PropertyInfo { get { throw null; } }
|
||||||
public bool Equals(Microsoft.AspNetCore.Mvc.ModelBinding.Metadata.ModelMetadataIdentity other) { throw null; }
|
public bool Equals(Microsoft.AspNetCore.Mvc.ModelBinding.Metadata.ModelMetadataIdentity other) { throw null; }
|
||||||
public override bool Equals(object obj) { throw null; }
|
public override bool Equals(object obj) { throw null; }
|
||||||
public static Microsoft.AspNetCore.Mvc.ModelBinding.Metadata.ModelMetadataIdentity ForParameter(System.Reflection.ParameterInfo parameter) { throw null; }
|
public static Microsoft.AspNetCore.Mvc.ModelBinding.Metadata.ModelMetadataIdentity ForParameter(System.Reflection.ParameterInfo parameter) { throw null; }
|
||||||
public static Microsoft.AspNetCore.Mvc.ModelBinding.Metadata.ModelMetadataIdentity ForParameter(System.Reflection.ParameterInfo parameter, System.Type modelType) { throw null; }
|
public static Microsoft.AspNetCore.Mvc.ModelBinding.Metadata.ModelMetadataIdentity ForParameter(System.Reflection.ParameterInfo parameter, System.Type modelType) { throw null; }
|
||||||
|
public static Microsoft.AspNetCore.Mvc.ModelBinding.Metadata.ModelMetadataIdentity ForProperty(System.Reflection.PropertyInfo propertyInfo, System.Type modelType, System.Type containerType) { throw null; }
|
||||||
|
[System.ObsoleteAttribute("This API is obsolete and may be removed in a future release.")]
|
||||||
public static Microsoft.AspNetCore.Mvc.ModelBinding.Metadata.ModelMetadataIdentity ForProperty(System.Type modelType, string name, System.Type containerType) { throw null; }
|
public static Microsoft.AspNetCore.Mvc.ModelBinding.Metadata.ModelMetadataIdentity ForProperty(System.Type modelType, string name, System.Type containerType) { throw null; }
|
||||||
public static Microsoft.AspNetCore.Mvc.ModelBinding.Metadata.ModelMetadataIdentity ForType(System.Type modelType) { throw null; }
|
public static Microsoft.AspNetCore.Mvc.ModelBinding.Metadata.ModelMetadataIdentity ForType(System.Type modelType) { throw null; }
|
||||||
public override int GetHashCode() { throw null; }
|
public override int GetHashCode() { throw null; }
|
||||||
|
|
|
||||||
|
|
@ -17,12 +17,12 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
||||||
Type modelType,
|
Type modelType,
|
||||||
string name = null,
|
string name = null,
|
||||||
Type containerType = null,
|
Type containerType = null,
|
||||||
ParameterInfo parameterInfo = null)
|
object fieldInfo = null)
|
||||||
{
|
{
|
||||||
ModelType = modelType;
|
ModelType = modelType;
|
||||||
Name = name;
|
Name = name;
|
||||||
ContainerType = containerType;
|
ContainerType = containerType;
|
||||||
ParameterInfo = parameterInfo;
|
FieldInfo = fieldInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -47,6 +47,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
||||||
/// <param name="name">The name of the property.</param>
|
/// <param name="name">The name of the property.</param>
|
||||||
/// <param name="containerType">The container type of the model property.</param>
|
/// <param name="containerType">The container type of the model property.</param>
|
||||||
/// <returns>A <see cref="ModelMetadataIdentity"/>.</returns>
|
/// <returns>A <see cref="ModelMetadataIdentity"/>.</returns>
|
||||||
|
[Obsolete("This API is obsolete and may be removed in a future release.")]
|
||||||
public static ModelMetadataIdentity ForProperty(
|
public static ModelMetadataIdentity ForProperty(
|
||||||
Type modelType,
|
Type modelType,
|
||||||
string name,
|
string name,
|
||||||
|
|
@ -70,6 +71,36 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
||||||
return new ModelMetadataIdentity(modelType, name, containerType);
|
return new ModelMetadataIdentity(modelType, name, containerType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a <see cref="ModelMetadataIdentity"/> for the provided property.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="modelType">The model type.</param>
|
||||||
|
/// <param name="propertyInfo">The property.</param>
|
||||||
|
/// <param name="containerType">The container type of the model property.</param>
|
||||||
|
/// <returns>A <see cref="ModelMetadataIdentity"/>.</returns>
|
||||||
|
public static ModelMetadataIdentity ForProperty(
|
||||||
|
PropertyInfo propertyInfo,
|
||||||
|
Type modelType,
|
||||||
|
Type containerType)
|
||||||
|
{
|
||||||
|
if (propertyInfo == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(propertyInfo));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (modelType == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(modelType));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (containerType == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(containerType));
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ModelMetadataIdentity(modelType, propertyInfo.Name, containerType, fieldInfo: propertyInfo);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a <see cref="ModelMetadataIdentity"/> for the provided parameter.
|
/// Creates a <see cref="ModelMetadataIdentity"/> for the provided parameter.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -97,7 +128,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
||||||
throw new ArgumentNullException(nameof(modelType));
|
throw new ArgumentNullException(nameof(modelType));
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ModelMetadataIdentity(modelType, parameter.Name, parameterInfo: parameter);
|
return new ModelMetadataIdentity(modelType, parameter.Name, fieldInfo: parameter);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -139,11 +170,19 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Name { get; }
|
public string Name { get; }
|
||||||
|
|
||||||
|
private object FieldInfo { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a descriptor for the parameter, or <c>null</c> if this instance
|
/// Gets a descriptor for the parameter, or <c>null</c> if this instance
|
||||||
/// does not represent a parameter.
|
/// does not represent a parameter.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ParameterInfo ParameterInfo { get; }
|
public ParameterInfo ParameterInfo => FieldInfo as ParameterInfo;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a descriptor for the property, or <c>null</c> if this instance
|
||||||
|
/// does not represent a property.
|
||||||
|
/// </summary>
|
||||||
|
public PropertyInfo PropertyInfo => FieldInfo as PropertyInfo;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public bool Equals(ModelMetadataIdentity other)
|
public bool Equals(ModelMetadataIdentity other)
|
||||||
|
|
@ -152,7 +191,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
||||||
ContainerType == other.ContainerType &&
|
ContainerType == other.ContainerType &&
|
||||||
ModelType == other.ModelType &&
|
ModelType == other.ModelType &&
|
||||||
Name == other.Name &&
|
Name == other.Name &&
|
||||||
ParameterInfo == other.ParameterInfo;
|
ParameterInfo == other.ParameterInfo &&
|
||||||
|
PropertyInfo == other.PropertyInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|
@ -170,6 +210,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
||||||
hash.Add(ModelType);
|
hash.Add(ModelType);
|
||||||
hash.Add(Name, StringComparer.Ordinal);
|
hash.Add(Name, StringComparer.Ordinal);
|
||||||
hash.Add(ParameterInfo);
|
hash.Add(ParameterInfo);
|
||||||
|
hash.Add(PropertyInfo);
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -270,7 +270,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
||||||
public void ContainerType_ReturnExpectedMetadata_ForProperty()
|
public void ContainerType_ReturnExpectedMetadata_ForProperty()
|
||||||
{
|
{
|
||||||
// Arrange & Act
|
// Arrange & Act
|
||||||
var metadata = new TestModelMetadata(typeof(int), nameof(string.Length), typeof(string));
|
var property = typeof(string).GetProperty(nameof(string.Length));
|
||||||
|
var metadata = new TestModelMetadata(property, typeof(int), typeof(string));
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(typeof(string), metadata.ContainerType);
|
Assert.Equal(typeof(string), metadata.ContainerType);
|
||||||
|
|
@ -308,7 +309,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
||||||
public void Names_ReturnExpectedMetadata_ForProperty()
|
public void Names_ReturnExpectedMetadata_ForProperty()
|
||||||
{
|
{
|
||||||
// Arrange & Act
|
// Arrange & Act
|
||||||
var metadata = new TestModelMetadata(typeof(int), nameof(string.Length), typeof(string));
|
var property = typeof(string).GetProperty(nameof(string.Length));
|
||||||
|
var metadata = new TestModelMetadata(property, typeof(int), typeof(string));
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(nameof(string.Length), metadata.Name);
|
Assert.Equal(nameof(string.Length), metadata.Name);
|
||||||
|
|
@ -322,7 +324,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
||||||
public void GetDisplayName_ReturnsDisplayName_IfSet()
|
public void GetDisplayName_ReturnsDisplayName_IfSet()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var metadata = new TestModelMetadata(typeof(int), "Length", typeof(string));
|
var property = typeof(string).GetProperty(nameof(string.Length));
|
||||||
|
var metadata = new TestModelMetadata(property, typeof(int), typeof(string));
|
||||||
metadata.SetDisplayName("displayName");
|
metadata.SetDisplayName("displayName");
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -351,7 +354,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
||||||
public void GetDisplayName_ReturnsPropertyName_WhenSetAndDisplayNameIsNull()
|
public void GetDisplayName_ReturnsPropertyName_WhenSetAndDisplayNameIsNull()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var metadata = new TestModelMetadata(typeof(int), "Length", typeof(string));
|
var property = typeof(string).GetProperty(nameof(string.Length));
|
||||||
|
var metadata = new TestModelMetadata(property, typeof(int), typeof(string));
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = metadata.GetDisplayName();
|
var result = metadata.GetDisplayName();
|
||||||
|
|
@ -419,8 +423,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public TestModelMetadata(Type modelType, string propertyName, Type containerType)
|
public TestModelMetadata(PropertyInfo propertyInfo, Type modelType, Type containerType)
|
||||||
: base(ModelMetadataIdentity.ForProperty(modelType, propertyName, containerType))
|
: base(ModelMetadataIdentity.ForProperty(propertyInfo, modelType, containerType))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@ using System.Text.Json;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Mvc.Formatters.Json;
|
using Microsoft.AspNetCore.Mvc.Formatters.Json;
|
||||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Mvc.Formatters
|
namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
|
|
@ -87,6 +86,16 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
|
|
||||||
return InputFormatterResult.Failure();
|
return InputFormatterResult.Failure();
|
||||||
}
|
}
|
||||||
|
catch (Exception exception) when (exception is FormatException || exception is OverflowException)
|
||||||
|
{
|
||||||
|
// The code in System.Text.Json never throws these exceptions. However a custom converter could produce these errors for instance when
|
||||||
|
// parsing a value. These error messages are considered safe to report to users using ModelState.
|
||||||
|
|
||||||
|
context.ModelState.TryAddModelError(string.Empty, exception, context.Metadata);
|
||||||
|
Log.JsonInputException(_logger, exception);
|
||||||
|
|
||||||
|
return InputFormatterResult.Failure();
|
||||||
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
if (inputStream is TranscodingReadStream transcoding)
|
if (inputStream is TranscodingReadStream transcoding)
|
||||||
|
|
|
||||||
|
|
@ -190,7 +190,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
||||||
private ModelMetadataCacheEntry GetCacheEntry(PropertyInfo property, Type modelType)
|
private ModelMetadataCacheEntry GetCacheEntry(PropertyInfo property, Type modelType)
|
||||||
{
|
{
|
||||||
return _typeCache.GetOrAdd(
|
return _typeCache.GetOrAdd(
|
||||||
ModelMetadataIdentity.ForProperty(modelType, property.Name, property.DeclaringType),
|
ModelMetadataIdentity.ForProperty(property, modelType, property.DeclaringType),
|
||||||
_cacheEntryFactory);
|
_cacheEntryFactory);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -275,8 +275,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
||||||
var propertyHelper = propertyHelpers[i];
|
var propertyHelper = propertyHelpers[i];
|
||||||
|
|
||||||
var propertyKey = ModelMetadataIdentity.ForProperty(
|
var propertyKey = ModelMetadataIdentity.ForProperty(
|
||||||
|
propertyHelper.Property,
|
||||||
propertyHelper.Property.PropertyType,
|
propertyHelper.Property.PropertyType,
|
||||||
propertyHelper.Name,
|
|
||||||
key.ModelType);
|
key.ModelType);
|
||||||
|
|
||||||
var propertyEntry = CreateSinglePropertyDetails(propertyKey, propertyHelper);
|
var propertyEntry = CreateSinglePropertyDetails(propertyKey, propertyHelper);
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// 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.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
|
||||||
using Microsoft.AspNetCore.Http;
|
|
||||||
using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata;
|
using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata;
|
||||||
using Moq;
|
using Moq;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
@ -27,7 +25,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
||||||
|
|
||||||
var context = new DefaultModelBindingContext();
|
var context = new DefaultModelBindingContext();
|
||||||
|
|
||||||
|
#pragma warning disable CS0618 // Type or member is obsolete
|
||||||
var identity = ModelMetadataIdentity.ForProperty(typeof(int), property, typeof(string));
|
var identity = ModelMetadataIdentity.ForProperty(typeof(int), property, typeof(string));
|
||||||
|
#pragma warning restore CS0618 // Type or member is obsolete
|
||||||
context.ModelMetadata = new Mock<ModelMetadata>(identity).Object;
|
context.ModelMetadata = new Mock<ModelMetadata>(identity).Object;
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
|
||||||
|
|
@ -334,7 +334,8 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
// Assert
|
// Assert
|
||||||
Assert.True(result.HasError, "Model should have produced an error!");
|
Assert.True(result.HasError, "Model should have produced an error!");
|
||||||
Assert.Collection(formatterContext.ModelState.OrderBy(k => k.Key),
|
Assert.Collection(formatterContext.ModelState.OrderBy(k => k.Key),
|
||||||
kvp => {
|
kvp =>
|
||||||
|
{
|
||||||
Assert.Equal(expectedValue, kvp.Key);
|
Assert.Equal(expectedValue, kvp.Key);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
@ -81,6 +83,48 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task ReadAsync_DoesNotThrowFormatException()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var formatter = GetInputFormatter();
|
||||||
|
|
||||||
|
var contentBytes = Encoding.UTF8.GetBytes("{\"dateValue\":\"not-a-date\"}");
|
||||||
|
var httpContext = GetHttpContext(contentBytes);
|
||||||
|
|
||||||
|
var formatterContext = CreateInputFormatterContext(typeof(TypeWithBadConverters), httpContext);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await formatter.ReadAsync(formatterContext);
|
||||||
|
|
||||||
|
Assert.False(formatterContext.ModelState.IsValid);
|
||||||
|
var kvp = Assert.Single(formatterContext.ModelState);
|
||||||
|
Assert.Empty(kvp.Key);
|
||||||
|
var error = Assert.Single(kvp.Value.Errors);
|
||||||
|
Assert.Equal("The supplied value is invalid.", error.ErrorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task ReadAsync_DoesNotThrowOverflowException()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var formatter = GetInputFormatter();
|
||||||
|
|
||||||
|
var contentBytes = Encoding.UTF8.GetBytes("{\"shortValue\":\"32768\"}");
|
||||||
|
var httpContext = GetHttpContext(contentBytes);
|
||||||
|
|
||||||
|
var formatterContext = CreateInputFormatterContext(typeof(TypeWithBadConverters), httpContext);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await formatter.ReadAsync(formatterContext);
|
||||||
|
|
||||||
|
Assert.False(formatterContext.ModelState.IsValid);
|
||||||
|
var kvp = Assert.Single(formatterContext.ModelState);
|
||||||
|
Assert.Empty(kvp.Key);
|
||||||
|
var error = Assert.Single(kvp.Value.Errors);
|
||||||
|
Assert.Equal("The supplied value is invalid.", error.ErrorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
protected override TextInputFormatter GetInputFormatter()
|
protected override TextInputFormatter GetInputFormatter()
|
||||||
{
|
{
|
||||||
return new SystemTextJsonInputFormatter(new JsonOptions(), LoggerFactory.CreateLogger<SystemTextJsonInputFormatter>());
|
return new SystemTextJsonInputFormatter(new JsonOptions(), LoggerFactory.CreateLogger<SystemTextJsonInputFormatter>());
|
||||||
|
|
@ -99,5 +143,40 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
internal override string ReadAsync_InvalidComplexArray_AddsOverflowErrorsToModelState_Expected => "$[1].Small";
|
internal override string ReadAsync_InvalidComplexArray_AddsOverflowErrorsToModelState_Expected => "$[1].Small";
|
||||||
|
|
||||||
internal override string ReadAsync_ComplexPoco_Expected => "$.Person.Numbers[2]";
|
internal override string ReadAsync_ComplexPoco_Expected => "$.Person.Numbers[2]";
|
||||||
|
|
||||||
|
private class TypeWithBadConverters
|
||||||
|
{
|
||||||
|
[JsonConverter(typeof(DateTimeConverter))]
|
||||||
|
public DateTime DateValue { get; set; }
|
||||||
|
|
||||||
|
[JsonConverter(typeof(ShortConverter))]
|
||||||
|
public short ShortValue { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ShortConverter : JsonConverter<short>
|
||||||
|
{
|
||||||
|
public override short Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||||
|
{
|
||||||
|
return short.Parse(reader.GetString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Write(Utf8JsonWriter writer, short value, JsonSerializerOptions options)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class DateTimeConverter : JsonConverter<DateTime>
|
||||||
|
{
|
||||||
|
public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||||
|
{
|
||||||
|
return DateTime.Parse(reader.GetString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -161,7 +161,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
||||||
};
|
};
|
||||||
|
|
||||||
var context = new BindingMetadataProviderContext(
|
var context = new BindingMetadataProviderContext(
|
||||||
ModelMetadataIdentity.ForProperty(typeof(int), "Length", typeof(string)),
|
ModelMetadataIdentity.ForProperty(typeof(string).GetProperty(nameof(string.Length)), typeof(int), typeof(string)),
|
||||||
new ModelAttributes(new object[0], propertyAttributes, null));
|
new ModelAttributes(new object[0], propertyAttributes, null));
|
||||||
|
|
||||||
var provider = new DefaultBindingMetadataProvider();
|
var provider = new DefaultBindingMetadataProvider();
|
||||||
|
|
@ -184,7 +184,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
||||||
};
|
};
|
||||||
|
|
||||||
var context = new BindingMetadataProviderContext(
|
var context = new BindingMetadataProviderContext(
|
||||||
ModelMetadataIdentity.ForProperty(typeof(int), "Length", typeof(string)),
|
ModelMetadataIdentity.ForProperty(typeof(string).GetProperty(nameof(string.Length)), typeof(int), typeof(string)),
|
||||||
new ModelAttributes(new object[0], propertyAttributes, null));
|
new ModelAttributes(new object[0], propertyAttributes, null));
|
||||||
|
|
||||||
var provider = new DefaultBindingMetadataProvider();
|
var provider = new DefaultBindingMetadataProvider();
|
||||||
|
|
@ -207,7 +207,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
||||||
};
|
};
|
||||||
|
|
||||||
var context = new BindingMetadataProviderContext(
|
var context = new BindingMetadataProviderContext(
|
||||||
ModelMetadataIdentity.ForProperty(typeof(int), "Length", typeof(string)),
|
ModelMetadataIdentity.ForProperty(typeof(string).GetProperty(nameof(string.Length)), typeof(int), typeof(string)),
|
||||||
new ModelAttributes(new object[0], propertyAttributes, null));
|
new ModelAttributes(new object[0], propertyAttributes, null));
|
||||||
|
|
||||||
var provider = new DefaultBindingMetadataProvider();
|
var provider = new DefaultBindingMetadataProvider();
|
||||||
|
|
@ -230,7 +230,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
||||||
};
|
};
|
||||||
|
|
||||||
var context = new BindingMetadataProviderContext(
|
var context = new BindingMetadataProviderContext(
|
||||||
ModelMetadataIdentity.ForProperty(typeof(int), "Length", typeof(string)),
|
ModelMetadataIdentity.ForProperty(typeof(string).GetProperty(nameof(string.Length)), typeof(int), typeof(string)),
|
||||||
new ModelAttributes(new object[0], propertyAttributes, null));
|
new ModelAttributes(new object[0], propertyAttributes, null));
|
||||||
|
|
||||||
var provider = new DefaultBindingMetadataProvider();
|
var provider = new DefaultBindingMetadataProvider();
|
||||||
|
|
@ -253,7 +253,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
||||||
};
|
};
|
||||||
|
|
||||||
var context = new BindingMetadataProviderContext(
|
var context = new BindingMetadataProviderContext(
|
||||||
ModelMetadataIdentity.ForProperty(typeof(int), "Length", typeof(string)),
|
ModelMetadataIdentity.ForProperty(typeof(string).GetProperty(nameof(string.Length)), typeof(int), typeof(string)),
|
||||||
new ModelAttributes(new object[0], propertyAttributes, null));
|
new ModelAttributes(new object[0], propertyAttributes, null));
|
||||||
|
|
||||||
var provider = new DefaultBindingMetadataProvider();
|
var provider = new DefaultBindingMetadataProvider();
|
||||||
|
|
@ -420,7 +420,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
||||||
};
|
};
|
||||||
|
|
||||||
var context = new BindingMetadataProviderContext(
|
var context = new BindingMetadataProviderContext(
|
||||||
ModelMetadataIdentity.ForProperty(typeof(int), "Length", typeof(string)),
|
ModelMetadataIdentity.ForProperty(typeof(string).GetProperty(nameof(string.Length)), typeof(int), typeof(string)),
|
||||||
new ModelAttributes(new object[0], propertyAttributes, null));
|
new ModelAttributes(new object[0], propertyAttributes, null));
|
||||||
|
|
||||||
var provider = new DefaultBindingMetadataProvider();
|
var provider = new DefaultBindingMetadataProvider();
|
||||||
|
|
@ -438,7 +438,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var context = new BindingMetadataProviderContext(
|
var context = new BindingMetadataProviderContext(
|
||||||
ModelMetadataIdentity.ForProperty(typeof(string), "Property", typeof(BindRequiredOnClass)),
|
ModelMetadataIdentity.ForProperty(typeof(BindRequiredOnClass).GetProperty(nameof(BindRequiredOnClass.Property)), typeof(int), typeof(BindRequiredOnClass)),
|
||||||
new ModelAttributes(new object[0], new object[0], null));
|
new ModelAttributes(new object[0], new object[0], null));
|
||||||
|
|
||||||
var provider = new DefaultBindingMetadataProvider();
|
var provider = new DefaultBindingMetadataProvider();
|
||||||
|
|
@ -456,7 +456,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var context = new BindingMetadataProviderContext(
|
var context = new BindingMetadataProviderContext(
|
||||||
ModelMetadataIdentity.ForProperty(typeof(string), "Property", typeof(BindNeverOnClass)),
|
ModelMetadataIdentity.ForProperty(typeof(BindNeverOnClass).GetProperty(nameof(BindNeverOnClass.Property)), typeof(int), typeof(BindNeverOnClass)),
|
||||||
new ModelAttributes(new object[0], new object[0], null));
|
new ModelAttributes(new object[0], new object[0], null));
|
||||||
|
|
||||||
var provider = new DefaultBindingMetadataProvider();
|
var provider = new DefaultBindingMetadataProvider();
|
||||||
|
|
@ -474,7 +474,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var context = new BindingMetadataProviderContext(
|
var context = new BindingMetadataProviderContext(
|
||||||
ModelMetadataIdentity.ForProperty(typeof(string), "Property", typeof(InheritedBindNeverOnClass)),
|
ModelMetadataIdentity.ForProperty(typeof(BindNeverOnClass).GetProperty(nameof(BindNeverOnClass.Property)), typeof(int), typeof(BindNeverOnClass)),
|
||||||
new ModelAttributes(new object[0], new object[0], null));
|
new ModelAttributes(new object[0], new object[0], null));
|
||||||
|
|
||||||
var provider = new DefaultBindingMetadataProvider();
|
var provider = new DefaultBindingMetadataProvider();
|
||||||
|
|
@ -497,7 +497,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
||||||
};
|
};
|
||||||
|
|
||||||
var context = new BindingMetadataProviderContext(
|
var context = new BindingMetadataProviderContext(
|
||||||
ModelMetadataIdentity.ForProperty(typeof(string), "Property", typeof(BindNeverOnClass)),
|
ModelMetadataIdentity.ForProperty(typeof(BindNeverOnClass).GetProperty(nameof(BindNeverOnClass.Property)), typeof(int), typeof(BindNeverOnClass)),
|
||||||
new ModelAttributes(new object[0], propertyAttributes, null));
|
new ModelAttributes(new object[0], propertyAttributes, null));
|
||||||
|
|
||||||
var provider = new DefaultBindingMetadataProvider();
|
var provider = new DefaultBindingMetadataProvider();
|
||||||
|
|
@ -520,7 +520,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
||||||
};
|
};
|
||||||
|
|
||||||
var context = new BindingMetadataProviderContext(
|
var context = new BindingMetadataProviderContext(
|
||||||
ModelMetadataIdentity.ForProperty(typeof(string), "Property", typeof(BindNeverOnClass)),
|
ModelMetadataIdentity.ForProperty(typeof(BindNeverOnClass).GetProperty(nameof(BindNeverOnClass.Property)), typeof(int), typeof(BindNeverOnClass)),
|
||||||
new ModelAttributes(new object[0], propertyAttributes, null));
|
new ModelAttributes(new object[0], propertyAttributes, null));
|
||||||
|
|
||||||
var provider = new DefaultBindingMetadataProvider();
|
var provider = new DefaultBindingMetadataProvider();
|
||||||
|
|
@ -543,7 +543,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
||||||
};
|
};
|
||||||
|
|
||||||
var context = new BindingMetadataProviderContext(
|
var context = new BindingMetadataProviderContext(
|
||||||
ModelMetadataIdentity.ForProperty(typeof(string), "Property", typeof(InheritedBindNeverOnClass)),
|
ModelMetadataIdentity.ForProperty(typeof(InheritedBindNeverOnClass).GetProperty(nameof(InheritedBindNeverOnClass.Property)), typeof(int), typeof(InheritedBindNeverOnClass)),
|
||||||
new ModelAttributes(new object[0], propertyAttributes, null));
|
new ModelAttributes(new object[0], propertyAttributes, null));
|
||||||
|
|
||||||
var provider = new DefaultBindingMetadataProvider();
|
var provider = new DefaultBindingMetadataProvider();
|
||||||
|
|
@ -566,7 +566,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
||||||
};
|
};
|
||||||
|
|
||||||
var context = new BindingMetadataProviderContext(
|
var context = new BindingMetadataProviderContext(
|
||||||
ModelMetadataIdentity.ForProperty(typeof(string), "Property", typeof(BindRequiredOnClass)),
|
ModelMetadataIdentity.ForProperty(typeof(BindRequiredOnClass).GetProperty(nameof(BindRequiredOnClass.Property)), typeof(int), typeof(BindRequiredOnClass)),
|
||||||
new ModelAttributes(new object[0], propertyAttributes, null));
|
new ModelAttributes(new object[0], propertyAttributes, null));
|
||||||
|
|
||||||
var provider = new DefaultBindingMetadataProvider();
|
var provider = new DefaultBindingMetadataProvider();
|
||||||
|
|
@ -585,7 +585,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var context = new BindingMetadataProviderContext(
|
var context = new BindingMetadataProviderContext(
|
||||||
ModelMetadataIdentity.ForProperty(typeof(string), "Property", typeof(BindRequiredOverridesInheritedBindNever)),
|
ModelMetadataIdentity.ForProperty(typeof(BindRequiredOverridesInheritedBindNever).GetProperty(nameof(BindRequiredOverridesInheritedBindNever.Property)), typeof(int), typeof(BindRequiredOverridesInheritedBindNever)),
|
||||||
new ModelAttributes(new object[0], new object[0], null));
|
new ModelAttributes(new object[0], new object[0], null));
|
||||||
|
|
||||||
var provider = new DefaultBindingMetadataProvider();
|
var provider = new DefaultBindingMetadataProvider();
|
||||||
|
|
@ -641,7 +641,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
||||||
};
|
};
|
||||||
|
|
||||||
var context = new BindingMetadataProviderContext(
|
var context = new BindingMetadataProviderContext(
|
||||||
ModelMetadataIdentity.ForProperty(typeof(int), "Length", typeof(string)),
|
ModelMetadataIdentity.ForProperty(typeof(string).GetProperty(nameof(string.Length)), typeof(int), typeof(string)),
|
||||||
new ModelAttributes(typeAttributes, new object[0], null));
|
new ModelAttributes(typeAttributes, new object[0], null));
|
||||||
|
|
||||||
// These values shouldn't be changed since this is a Type-Metadata
|
// These values shouldn't be changed since this is a Type-Metadata
|
||||||
|
|
|
||||||
|
|
@ -103,7 +103,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
||||||
var provider = new EmptyModelMetadataProvider();
|
var provider = new EmptyModelMetadataProvider();
|
||||||
var detailsProvider = new EmptyCompositeMetadataDetailsProvider();
|
var detailsProvider = new EmptyCompositeMetadataDetailsProvider();
|
||||||
|
|
||||||
var key = ModelMetadataIdentity.ForProperty(typeof(string), "Message", typeof(Exception));
|
var key = ModelMetadataIdentity.ForProperty(typeof(Exception).GetProperty(nameof(Exception.Message)), typeof(string), typeof(Exception));
|
||||||
var cache = new DefaultMetadataDetails(key, new ModelAttributes(new object[0], new object[0], null));
|
var cache = new DefaultMetadataDetails(key, new ModelAttributes(new object[0], new object[0], null));
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -123,8 +123,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
||||||
var detailsProvider = new EmptyCompositeMetadataDetailsProvider();
|
var detailsProvider = new EmptyCompositeMetadataDetailsProvider();
|
||||||
|
|
||||||
var key = ModelMetadataIdentity.ForProperty(
|
var key = ModelMetadataIdentity.ForProperty(
|
||||||
|
typeof(TypeWithProperties).GetProperty(nameof(TypeWithProperties.PublicGetPublicSetProperty)),
|
||||||
typeof(string),
|
typeof(string),
|
||||||
nameof(TypeWithProperties.PublicGetPublicSetProperty),
|
|
||||||
typeof(TypeWithProperties));
|
typeof(TypeWithProperties));
|
||||||
|
|
||||||
var attributes = new ModelAttributes(Array.Empty<object>(), Array.Empty<object>(), null);
|
var attributes = new ModelAttributes(Array.Empty<object>(), Array.Empty<object>(), null);
|
||||||
|
|
@ -160,8 +160,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
||||||
var detailsProvider = new EmptyCompositeMetadataDetailsProvider();
|
var detailsProvider = new EmptyCompositeMetadataDetailsProvider();
|
||||||
|
|
||||||
var key = ModelMetadataIdentity.ForProperty(
|
var key = ModelMetadataIdentity.ForProperty(
|
||||||
|
typeof(TypeWithProperties).GetProperty(nameof(TypeWithProperties.PublicGetPublicSetProperty)),
|
||||||
typeof(string),
|
typeof(string),
|
||||||
nameof(TypeWithProperties.PublicGetPublicSetProperty),
|
|
||||||
typeof(TypeWithProperties));
|
typeof(TypeWithProperties));
|
||||||
|
|
||||||
var attributes = new ModelAttributes(Array.Empty<object>(), Array.Empty<object>(), null);
|
var attributes = new ModelAttributes(Array.Empty<object>(), Array.Empty<object>(), null);
|
||||||
|
|
@ -197,8 +197,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
||||||
var detailsProvider = new EmptyCompositeMetadataDetailsProvider();
|
var detailsProvider = new EmptyCompositeMetadataDetailsProvider();
|
||||||
|
|
||||||
var key = ModelMetadataIdentity.ForProperty(
|
var key = ModelMetadataIdentity.ForProperty(
|
||||||
|
typeof(TypeWithProperties).GetProperty(nameof(TypeWithProperties.PublicGetPublicSetProperty)),
|
||||||
typeof(string),
|
typeof(string),
|
||||||
nameof(TypeWithProperties.PublicGetPublicSetProperty),
|
|
||||||
typeof(TypeWithProperties));
|
typeof(TypeWithProperties));
|
||||||
|
|
||||||
var attributes = new ModelAttributes(Array.Empty<object>(), Array.Empty<object>(), null);
|
var attributes = new ModelAttributes(Array.Empty<object>(), Array.Empty<object>(), null);
|
||||||
|
|
@ -393,19 +393,22 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
||||||
var provider = new Mock<IModelMetadataProvider>(MockBehavior.Strict);
|
var provider = new Mock<IModelMetadataProvider>(MockBehavior.Strict);
|
||||||
var detailsProvider = new EmptyCompositeMetadataDetailsProvider();
|
var detailsProvider = new EmptyCompositeMetadataDetailsProvider();
|
||||||
|
|
||||||
|
var prop1 = typeof(Exception).GetProperty(nameof(Exception.Message));
|
||||||
|
var prop2 = typeof(Exception).GetProperty(nameof(Exception.StackTrace));
|
||||||
|
|
||||||
var expectedProperties = new DefaultModelMetadata[]
|
var expectedProperties = new DefaultModelMetadata[]
|
||||||
{
|
{
|
||||||
new DefaultModelMetadata(
|
new DefaultModelMetadata(
|
||||||
provider.Object,
|
provider.Object,
|
||||||
detailsProvider,
|
detailsProvider,
|
||||||
new DefaultMetadataDetails(
|
new DefaultMetadataDetails(
|
||||||
ModelMetadataIdentity.ForProperty(typeof(int), "Prop1", typeof(string)),
|
ModelMetadataIdentity.ForProperty(prop1, typeof(int), typeof(string)),
|
||||||
attributes: new ModelAttributes(new object[0], new object[0], null))),
|
attributes: new ModelAttributes(new object[0], new object[0], null))),
|
||||||
new DefaultModelMetadata(
|
new DefaultModelMetadata(
|
||||||
provider.Object,
|
provider.Object,
|
||||||
detailsProvider,
|
detailsProvider,
|
||||||
new DefaultMetadataDetails(
|
new DefaultMetadataDetails(
|
||||||
ModelMetadataIdentity.ForProperty(typeof(int), "Prop2", typeof(string)),
|
ModelMetadataIdentity.ForProperty(prop2, typeof(int), typeof(string)),
|
||||||
attributes: new ModelAttributes(new object[0], new object[0], null))),
|
attributes: new ModelAttributes(new object[0], new object[0], null))),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -475,7 +478,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
||||||
provider.Object,
|
provider.Object,
|
||||||
detailsProvider,
|
detailsProvider,
|
||||||
new DefaultMetadataDetails(
|
new DefaultMetadataDetails(
|
||||||
|
#pragma warning disable CS0618 // Using the obsolete overload does not affect the intent of this test, but fixing it requires a lot of code churn.
|
||||||
ModelMetadataIdentity.ForProperty(typeof(int), originalName, typeof(string)),
|
ModelMetadataIdentity.ForProperty(typeof(int), originalName, typeof(string)),
|
||||||
|
#pragma warning restore CS0618 // Type or member is obsolete
|
||||||
attributes: new ModelAttributes(new object[0], new object[0], null))));
|
attributes: new ModelAttributes(new object[0], new object[0], null))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -575,7 +580,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
||||||
foreach (var kvp in originalNamesAndOrders)
|
foreach (var kvp in originalNamesAndOrders)
|
||||||
{
|
{
|
||||||
var propertyCache = new DefaultMetadataDetails(
|
var propertyCache = new DefaultMetadataDetails(
|
||||||
|
#pragma warning disable CS0618 // Using the obsolete overload does not affect the intent of this test, but fixing it requires a lot of code churn.
|
||||||
ModelMetadataIdentity.ForProperty(typeof(int), kvp.Key, typeof(string)),
|
ModelMetadataIdentity.ForProperty(typeof(int), kvp.Key, typeof(string)),
|
||||||
|
#pragma warning restore CS0618 // Type or member is obsolete
|
||||||
attributes: new ModelAttributes(new object[0], new object[0], null))
|
attributes: new ModelAttributes(new object[0], new object[0], null))
|
||||||
{
|
{
|
||||||
DisplayMetadata = new DisplayMetadata(),
|
DisplayMetadata = new DisplayMetadata(),
|
||||||
|
|
@ -934,7 +941,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
||||||
// Arrange
|
// Arrange
|
||||||
var property = GetType()
|
var property = GetType()
|
||||||
.GetProperty(nameof(CalculateHasValidators_PropertyMetadata_TypeHasNoValidatorsProperty), BindingFlags.Static | BindingFlags.NonPublic);
|
.GetProperty(nameof(CalculateHasValidators_PropertyMetadata_TypeHasNoValidatorsProperty), BindingFlags.Static | BindingFlags.NonPublic);
|
||||||
var modelIdentity = ModelMetadataIdentity.ForProperty(property.PropertyType, property.Name, GetType());
|
var modelIdentity = ModelMetadataIdentity.ForProperty(property, property.PropertyType, GetType());
|
||||||
var modelMetadata = CreateModelMetadata(modelIdentity, Mock.Of<IModelMetadataProvider>(), false);
|
var modelMetadata = CreateModelMetadata(modelIdentity, Mock.Of<IModelMetadataProvider>(), false);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -997,7 +1004,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
||||||
var metadataProvider = new Mock<IModelMetadataProvider>();
|
var metadataProvider = new Mock<IModelMetadataProvider>();
|
||||||
var modelMetadata = CreateModelMetadata(modelIdentity, metadataProvider.Object, false);
|
var modelMetadata = CreateModelMetadata(modelIdentity, metadataProvider.Object, false);
|
||||||
|
|
||||||
var propertyIdentity = ModelMetadataIdentity.ForProperty(typeof(int), nameof(TypeWithProperties.PublicGetPublicSetProperty), typeof(string));
|
var property = typeof(TypeWithProperties).GetProperty(nameof(TypeWithProperties.PublicGetPublicSetProperty));
|
||||||
|
var propertyIdentity = ModelMetadataIdentity.ForProperty(property, typeof(int), typeof(TypeWithProperties));
|
||||||
var propertyMetadata = new Mock<ModelMetadata>(propertyIdentity);
|
var propertyMetadata = new Mock<ModelMetadata>(propertyIdentity);
|
||||||
|
|
||||||
metadataProvider
|
metadataProvider
|
||||||
|
|
@ -1021,10 +1029,10 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
||||||
var metadataProvider = new Mock<IModelMetadataProvider>();
|
var metadataProvider = new Mock<IModelMetadataProvider>();
|
||||||
var modelMetadata = CreateModelMetadata(modelIdentity, metadataProvider.Object, false);
|
var modelMetadata = CreateModelMetadata(modelIdentity, metadataProvider.Object, false);
|
||||||
|
|
||||||
var property1Identity = ModelMetadataIdentity.ForProperty(typeof(int), nameof(TypeWithProperties.PublicGetPublicSetProperty), typeof(string));
|
var property1Identity = ModelMetadataIdentity.ForProperty(modelType.GetProperty(nameof(TypeWithProperties.PublicGetPublicSetProperty)), typeof(int), modelType);
|
||||||
var property1Metadata = CreateModelMetadata(property1Identity, metadataProvider.Object, false);
|
var property1Metadata = CreateModelMetadata(property1Identity, metadataProvider.Object, false);
|
||||||
|
|
||||||
var property2Identity = ModelMetadataIdentity.ForProperty(typeof(int), nameof(TypeWithProperties.PublicGetProtectedSetProperty), typeof(string));
|
var property2Identity = ModelMetadataIdentity.ForProperty(modelType.GetProperty(nameof(TypeWithProperties.PublicGetProtectedSetProperty)), typeof(int), modelType);
|
||||||
var property2Metadata = CreateModelMetadata(property2Identity, metadataProvider.Object, true);
|
var property2Metadata = CreateModelMetadata(property2Identity, metadataProvider.Object, true);
|
||||||
|
|
||||||
metadataProvider
|
metadataProvider
|
||||||
|
|
@ -1048,7 +1056,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
||||||
var metadataProvider = new Mock<IModelMetadataProvider>();
|
var metadataProvider = new Mock<IModelMetadataProvider>();
|
||||||
var modelMetadata = CreateModelMetadata(modelIdentity, metadataProvider.Object, false);
|
var modelMetadata = CreateModelMetadata(modelIdentity, metadataProvider.Object, false);
|
||||||
|
|
||||||
var propertyIdentity = ModelMetadataIdentity.ForProperty(typeof(int), nameof(TypeWithProperties.PublicGetPublicSetProperty), typeof(string));
|
var propertyIdentity = ModelMetadataIdentity.ForProperty(modelType.GetProperty(nameof(TypeWithProperties.PublicGetPublicSetProperty)), typeof(int), modelType);
|
||||||
var propertyMetadata = CreateModelMetadata(propertyIdentity, metadataProvider.Object, null);
|
var propertyMetadata = CreateModelMetadata(propertyIdentity, metadataProvider.Object, null);
|
||||||
|
|
||||||
metadataProvider
|
metadataProvider
|
||||||
|
|
@ -1072,10 +1080,10 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
||||||
var metadataProvider = new Mock<IModelMetadataProvider>();
|
var metadataProvider = new Mock<IModelMetadataProvider>();
|
||||||
var modelMetadata = CreateModelMetadata(modelIdentity, metadataProvider.Object, false);
|
var modelMetadata = CreateModelMetadata(modelIdentity, metadataProvider.Object, false);
|
||||||
|
|
||||||
var property1Identity = ModelMetadataIdentity.ForProperty(typeof(int), nameof(TypeWithProperties.PublicGetPublicSetProperty), modelType);
|
var property1Identity = ModelMetadataIdentity.ForProperty(modelType.GetProperty(nameof(TypeWithProperties.PublicGetPublicSetProperty)), typeof(int), modelType);
|
||||||
var property1Metadata = CreateModelMetadata(property1Identity, metadataProvider.Object, false);
|
var property1Metadata = CreateModelMetadata(property1Identity, metadataProvider.Object, false);
|
||||||
|
|
||||||
var property2Identity = ModelMetadataIdentity.ForProperty(typeof(int), nameof(TypeWithProperties.PublicGetProtectedSetProperty), modelType);
|
var property2Identity = ModelMetadataIdentity.ForProperty(modelType.GetProperty(nameof(TypeWithProperties.PublicGetProtectedSetProperty)), typeof(int), modelType);
|
||||||
var property2Metadata = CreateModelMetadata(property2Identity, metadataProvider.Object, false);
|
var property2Metadata = CreateModelMetadata(property2Identity, metadataProvider.Object, false);
|
||||||
|
|
||||||
metadataProvider
|
metadataProvider
|
||||||
|
|
@ -1099,18 +1107,19 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
||||||
var metadataProvider = new Mock<IModelMetadataProvider>();
|
var metadataProvider = new Mock<IModelMetadataProvider>();
|
||||||
var modelMetadata = CreateModelMetadata(modelIdentity, metadataProvider.Object, false);
|
var modelMetadata = CreateModelMetadata(modelIdentity, metadataProvider.Object, false);
|
||||||
|
|
||||||
var employeeId = ModelMetadataIdentity.ForProperty(typeof(int), nameof(Employee.Id), modelType);
|
var employeeId = ModelMetadataIdentity.ForProperty(modelType.GetProperty(nameof(Employee.Id)), typeof(int), modelType);
|
||||||
var employeeIdMetadata = CreateModelMetadata(modelIdentity, metadataProvider.Object, false);
|
var employeeIdMetadata = CreateModelMetadata(modelIdentity, metadataProvider.Object, false);
|
||||||
var employeeUnit = ModelMetadataIdentity.ForProperty(typeof(BusinessUnit), nameof(Employee.Unit), modelType);
|
var employeeUnit = ModelMetadataIdentity.ForProperty(modelType.GetProperty(nameof(Employee.Unit)), typeof(BusinessUnit), modelType);
|
||||||
var employeeUnitMetadata = CreateModelMetadata(employeeUnit, metadataProvider.Object, false);
|
var employeeUnitMetadata = CreateModelMetadata(employeeUnit, metadataProvider.Object, false);
|
||||||
var employeeManager = ModelMetadataIdentity.ForProperty(typeof(Employee), nameof(Employee.Unit), modelType);
|
var employeeManager = ModelMetadataIdentity.ForProperty(modelType.GetProperty(nameof(Employee.Manager)), typeof(Employee), modelType);
|
||||||
var employeeManagerMetadata = CreateModelMetadata(employeeManager, metadataProvider.Object, false);
|
var employeeManagerMetadata = CreateModelMetadata(employeeManager, metadataProvider.Object, false);
|
||||||
var employeeEmployees = ModelMetadataIdentity.ForProperty(typeof(List<Employee>), nameof(Employee.Employees), modelType);
|
var employeeEmployees = ModelMetadataIdentity.ForProperty(modelType.GetProperty(nameof(Employee.Employees)), typeof(List<Employee>), modelType);
|
||||||
var employeeEmployeesMetadata = CreateModelMetadata(employeeEmployees, metadataProvider.Object, false);
|
var employeeEmployeesMetadata = CreateModelMetadata(employeeEmployees, metadataProvider.Object, false);
|
||||||
|
|
||||||
var unitHead = ModelMetadataIdentity.ForProperty(typeof(Employee), nameof(BusinessUnit.Head), modelType);
|
var unitModel = typeof(BusinessUnit);
|
||||||
|
var unitHead = ModelMetadataIdentity.ForProperty(unitModel.GetProperty(nameof(BusinessUnit.Head)), typeof(Employee), unitModel);
|
||||||
var unitHeadMetadata = CreateModelMetadata(unitHead, metadataProvider.Object, false);
|
var unitHeadMetadata = CreateModelMetadata(unitHead, metadataProvider.Object, false);
|
||||||
var unitId = ModelMetadataIdentity.ForProperty(typeof(int), nameof(BusinessUnit.Id), modelType);
|
var unitId = ModelMetadataIdentity.ForProperty(unitModel.GetProperty(nameof(BusinessUnit.Id)), typeof(int), unitModel);
|
||||||
var unitIdMetadata = CreateModelMetadata(unitId, metadataProvider.Object, true); // BusinessUnit.Id has validators.
|
var unitIdMetadata = CreateModelMetadata(unitId, metadataProvider.Object, true); // BusinessUnit.Id has validators.
|
||||||
|
|
||||||
metadataProvider
|
metadataProvider
|
||||||
|
|
@ -1139,18 +1148,19 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
||||||
var metadataProvider = new Mock<IModelMetadataProvider>();
|
var metadataProvider = new Mock<IModelMetadataProvider>();
|
||||||
var modelMetadata = CreateModelMetadata(modelIdentity, metadataProvider.Object, false);
|
var modelMetadata = CreateModelMetadata(modelIdentity, metadataProvider.Object, false);
|
||||||
|
|
||||||
var employeeId = ModelMetadataIdentity.ForProperty(typeof(int), nameof(Employee.Id), modelType);
|
var employeeId = ModelMetadataIdentity.ForProperty(modelType.GetProperty(nameof(Employee.Id)), typeof(int), modelType);
|
||||||
var employeeIdMetadata = CreateModelMetadata(modelIdentity, metadataProvider.Object, false);
|
var employeeIdMetadata = CreateModelMetadata(modelIdentity, metadataProvider.Object, false);
|
||||||
var employeeUnit = ModelMetadataIdentity.ForProperty(typeof(BusinessUnit), nameof(Employee.Unit), modelType);
|
var employeeUnit = ModelMetadataIdentity.ForProperty(modelType.GetProperty(nameof(Employee.Unit)), typeof(BusinessUnit), modelType);
|
||||||
var employeeUnitMetadata = CreateModelMetadata(employeeUnit, metadataProvider.Object, false);
|
var employeeUnitMetadata = CreateModelMetadata(employeeUnit, metadataProvider.Object, false);
|
||||||
var employeeManager = ModelMetadataIdentity.ForProperty(typeof(Employee), nameof(Employee.Unit), modelType);
|
var employeeManager = ModelMetadataIdentity.ForProperty(modelType.GetProperty(nameof(Employee.Manager)), typeof(Employee), modelType);
|
||||||
var employeeManagerMetadata = CreateModelMetadata(employeeManager, metadataProvider.Object, false);
|
var employeeManagerMetadata = CreateModelMetadata(employeeManager, metadataProvider.Object, false);
|
||||||
var employeeEmployees = ModelMetadataIdentity.ForProperty(typeof(List<Employee>), nameof(Employee.Employees), modelType);
|
var employeeEmployees = ModelMetadataIdentity.ForProperty(modelType.GetProperty(nameof(Employee.Employees)), typeof(List<Employee>), modelType);
|
||||||
var employeeEmployeesMetadata = CreateModelMetadata(employeeEmployees, metadataProvider.Object, false);
|
var employeeEmployeesMetadata = CreateModelMetadata(employeeEmployees, metadataProvider.Object, false);
|
||||||
|
|
||||||
var unitHead = ModelMetadataIdentity.ForProperty(typeof(Employee), nameof(BusinessUnit.Head), modelType);
|
var unitModel = typeof(BusinessUnit);
|
||||||
|
var unitHead = ModelMetadataIdentity.ForProperty(unitModel.GetProperty(nameof(BusinessUnit.Head)), typeof(Employee), unitModel);
|
||||||
var unitHeadMetadata = CreateModelMetadata(unitHead, metadataProvider.Object, true); // BusinessUnit.Head has validators
|
var unitHeadMetadata = CreateModelMetadata(unitHead, metadataProvider.Object, true); // BusinessUnit.Head has validators
|
||||||
var unitId = ModelMetadataIdentity.ForProperty(typeof(int), nameof(BusinessUnit.Id), modelType);
|
var unitId = ModelMetadataIdentity.ForProperty(unitModel.GetProperty(nameof(BusinessUnit.Id)), typeof(int), unitModel);
|
||||||
var unitIdMetadata = CreateModelMetadata(unitId, metadataProvider.Object, false);
|
var unitIdMetadata = CreateModelMetadata(unitId, metadataProvider.Object, false);
|
||||||
|
|
||||||
metadataProvider
|
metadataProvider
|
||||||
|
|
@ -1181,9 +1191,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
||||||
var metadataProvider = new Mock<IModelMetadataProvider>();
|
var metadataProvider = new Mock<IModelMetadataProvider>();
|
||||||
var modelMetadata = CreateModelMetadata(modelIdentity, metadataProvider.Object, false);
|
var modelMetadata = CreateModelMetadata(modelIdentity, metadataProvider.Object, false);
|
||||||
|
|
||||||
var employeeId = ModelMetadataIdentity.ForProperty(typeof(int), nameof(Employee.Id), modelType);
|
var employeeId = ModelMetadataIdentity.ForProperty(modelType.GetProperty(nameof(Employee.Id)), typeof(int), modelType);
|
||||||
var employeeIdMetadata = CreateModelMetadata(modelIdentity, metadataProvider.Object, false);
|
var employeeIdMetadata = CreateModelMetadata(modelIdentity, metadataProvider.Object, false);
|
||||||
var employeeEmployees = ModelMetadataIdentity.ForProperty(typeof(List<Employee>), nameof(Employee.Employees), modelType);
|
var employeeEmployees = ModelMetadataIdentity.ForProperty(modelType.GetProperty(nameof(Employee.Employees)), typeof(List<Employee>), modelType);
|
||||||
var employeeEmployeesMetadata = CreateModelMetadata(employeeEmployees, metadataProvider.Object, false);
|
var employeeEmployeesMetadata = CreateModelMetadata(employeeEmployees, metadataProvider.Object, false);
|
||||||
|
|
||||||
metadataProvider
|
metadataProvider
|
||||||
|
|
@ -1210,18 +1220,19 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
||||||
var metadataProvider = new Mock<IModelMetadataProvider>();
|
var metadataProvider = new Mock<IModelMetadataProvider>();
|
||||||
var modelMetadata = CreateModelMetadata(modelIdentity, metadataProvider.Object, false);
|
var modelMetadata = CreateModelMetadata(modelIdentity, metadataProvider.Object, false);
|
||||||
|
|
||||||
var employeeId = ModelMetadataIdentity.ForProperty(typeof(int), nameof(Employee.Id), modelType);
|
var employeeId = ModelMetadataIdentity.ForProperty(modelType.GetProperty(nameof(Employee.Id)), typeof(int), modelType);
|
||||||
var employeeIdMetadata = CreateModelMetadata(modelIdentity, metadataProvider.Object, false);
|
var employeeIdMetadata = CreateModelMetadata(modelIdentity, metadataProvider.Object, false);
|
||||||
var employeeUnit = ModelMetadataIdentity.ForProperty(typeof(BusinessUnit), nameof(Employee.Unit), modelType);
|
var employeeUnit = ModelMetadataIdentity.ForProperty(modelType.GetProperty(nameof(Employee.Unit)), typeof(BusinessUnit), modelType);
|
||||||
var employeeUnitMetadata = CreateModelMetadata(employeeUnit, metadataProvider.Object, false);
|
var employeeUnitMetadata = CreateModelMetadata(employeeUnit, metadataProvider.Object, false);
|
||||||
var employeeManager = ModelMetadataIdentity.ForProperty(typeof(Employee), nameof(Employee.Unit), modelType);
|
var employeeManager = ModelMetadataIdentity.ForProperty(modelType.GetProperty(nameof(Employee.Manager)), typeof(Employee), modelType);
|
||||||
var employeeManagerMetadata = CreateModelMetadata(employeeManager, metadataProvider.Object, false);
|
var employeeManagerMetadata = CreateModelMetadata(employeeManager, metadataProvider.Object, false);
|
||||||
var employeeEmployeesId = ModelMetadataIdentity.ForProperty(typeof(List<Employee>), nameof(Employee.Employees), modelType);
|
var employeeEmployeesId = ModelMetadataIdentity.ForProperty(modelType.GetProperty(nameof(Employee.Employees)), typeof(List<Employee>), modelType);
|
||||||
var employeeEmployeesIdMetadata = CreateModelMetadata(employeeEmployeesId, metadataProvider.Object, false);
|
var employeeEmployeesIdMetadata = CreateModelMetadata(employeeEmployeesId, metadataProvider.Object, false);
|
||||||
|
|
||||||
var unitHead = ModelMetadataIdentity.ForProperty(typeof(Employee), nameof(BusinessUnit.Head), modelType);
|
var unitModel = typeof(BusinessUnit);
|
||||||
|
var unitHead = ModelMetadataIdentity.ForProperty(unitModel.GetProperty(nameof(BusinessUnit.Head)), typeof(Employee), unitModel);
|
||||||
var unitHeadMetadata = CreateModelMetadata(unitHead, metadataProvider.Object, false);
|
var unitHeadMetadata = CreateModelMetadata(unitHead, metadataProvider.Object, false);
|
||||||
var unitId = ModelMetadataIdentity.ForProperty(typeof(int), nameof(BusinessUnit.Id), modelType);
|
var unitId = ModelMetadataIdentity.ForProperty(unitModel.GetProperty(nameof(BusinessUnit.Id)), typeof(int), unitModel);
|
||||||
var unitIdMetadata = CreateModelMetadata(unitId, metadataProvider.Object, false);
|
var unitIdMetadata = CreateModelMetadata(unitId, metadataProvider.Object, false);
|
||||||
|
|
||||||
metadataProvider
|
metadataProvider
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
||||||
var provider = new DefaultValidationMetadataProvider();
|
var provider = new DefaultValidationMetadataProvider();
|
||||||
|
|
||||||
var attributes = new Attribute[] { new ValidateNeverAttribute() };
|
var attributes = new Attribute[] { new ValidateNeverAttribute() };
|
||||||
var key = ModelMetadataIdentity.ForProperty(typeof(int), "Length", typeof(string));
|
var key = ModelMetadataIdentity.ForProperty(typeof(string).GetProperty(nameof(string.Length)), typeof(int), typeof(string));
|
||||||
var context = new ValidationMetadataProviderContext(key, new ModelAttributes(new object[0], attributes, null));
|
var context = new ValidationMetadataProviderContext(key, new ModelAttributes(new object[0], attributes, null));
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -37,7 +37,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
||||||
var provider = new DefaultValidationMetadataProvider();
|
var provider = new DefaultValidationMetadataProvider();
|
||||||
|
|
||||||
var attributes = new Attribute[] { new ValidateNeverAttribute() };
|
var attributes = new Attribute[] { new ValidateNeverAttribute() };
|
||||||
var key = ModelMetadataIdentity.ForProperty(typeof(int), "Length", typeof(string));
|
var key = ModelMetadataIdentity.ForProperty(typeof(string).GetProperty(nameof(string.Length)), typeof(int), typeof(string));
|
||||||
var context = new ValidationMetadataProviderContext(key, new ModelAttributes(attributes, new object[0], null));
|
var context = new ValidationMetadataProviderContext(key, new ModelAttributes(attributes, new object[0], null));
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -71,8 +71,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
||||||
var provider = new DefaultValidationMetadataProvider();
|
var provider = new DefaultValidationMetadataProvider();
|
||||||
|
|
||||||
var key = ModelMetadataIdentity.ForProperty(
|
var key = ModelMetadataIdentity.ForProperty(
|
||||||
|
typeof(ValidateNeverClass).GetProperty(nameof(ValidateNeverClass.ClassName)),
|
||||||
typeof(string),
|
typeof(string),
|
||||||
nameof(ValidateNeverClass.ClassName),
|
|
||||||
typeof(ValidateNeverClass));
|
typeof(ValidateNeverClass));
|
||||||
var context = new ValidationMetadataProviderContext(key, new ModelAttributes(new object[0], new object[0], null));
|
var context = new ValidationMetadataProviderContext(key, new ModelAttributes(new object[0], new object[0], null));
|
||||||
|
|
||||||
|
|
@ -93,8 +93,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
||||||
var provider = new DefaultValidationMetadataProvider();
|
var provider = new DefaultValidationMetadataProvider();
|
||||||
|
|
||||||
var key = ModelMetadataIdentity.ForProperty(
|
var key = ModelMetadataIdentity.ForProperty(
|
||||||
|
typeof(ValidateNeverSubclass).GetProperty(nameof(ValidateNeverSubclass.SubclassName)),
|
||||||
typeof(string),
|
typeof(string),
|
||||||
nameof(ValidateNeverSubclass.SubclassName),
|
|
||||||
typeof(ValidateNeverSubclass));
|
typeof(ValidateNeverSubclass));
|
||||||
var context = new ValidationMetadataProviderContext(key, new ModelAttributes(new object[0], new object[0], null));
|
var context = new ValidationMetadataProviderContext(key, new ModelAttributes(new object[0], new object[0], null));
|
||||||
|
|
||||||
|
|
@ -116,7 +116,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
||||||
|
|
||||||
var attribute = new TestClientModelValidationAttribute();
|
var attribute = new TestClientModelValidationAttribute();
|
||||||
var attributes = new Attribute[] { attribute };
|
var attributes = new Attribute[] { attribute };
|
||||||
var key = ModelMetadataIdentity.ForProperty(typeof(int), "Length", typeof(string));
|
var key = ModelMetadataIdentity.ForProperty(typeof(string).GetProperty(nameof(string.Length)), typeof(int), typeof(string));
|
||||||
var context = new ValidationMetadataProviderContext(key, new ModelAttributes(new object[0], attributes, null));
|
var context = new ValidationMetadataProviderContext(key, new ModelAttributes(new object[0], attributes, null));
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -135,7 +135,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
||||||
|
|
||||||
var attribute = new TestModelValidationAttribute();
|
var attribute = new TestModelValidationAttribute();
|
||||||
var attributes = new Attribute[] { attribute };
|
var attributes = new Attribute[] { attribute };
|
||||||
var key = ModelMetadataIdentity.ForProperty(typeof(int), "Length", typeof(string));
|
var key = ModelMetadataIdentity.ForProperty(typeof(string).GetProperty(nameof(string.Length)), typeof(int), typeof(string));
|
||||||
var context = new ValidationMetadataProviderContext(key, new ModelAttributes(new object[0], attributes, null));
|
var context = new ValidationMetadataProviderContext(key, new ModelAttributes(new object[0], attributes, null));
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -154,7 +154,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
||||||
|
|
||||||
var attribute = new TestValidationAttribute();
|
var attribute = new TestValidationAttribute();
|
||||||
var attributes = new Attribute[] { attribute };
|
var attributes = new Attribute[] { attribute };
|
||||||
var key = ModelMetadataIdentity.ForProperty(typeof(int), "Length", typeof(string));
|
var key = ModelMetadataIdentity.ForProperty(typeof(string).GetProperty(nameof(string.Length)), typeof(int), typeof(string));
|
||||||
var context = new ValidationMetadataProviderContext(key, new ModelAttributes(new object[0], attributes, null));
|
var context = new ValidationMetadataProviderContext(key, new ModelAttributes(new object[0], attributes, null));
|
||||||
context.ValidationMetadata.ValidatorMetadata.Add(attribute);
|
context.ValidationMetadata.ValidatorMetadata.Add(attribute);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
||||||
var provider = new ExcludeBindingMetadataProvider(typeof(string));
|
var provider = new ExcludeBindingMetadataProvider(typeof(string));
|
||||||
|
|
||||||
var key = ModelMetadataIdentity.ForProperty(
|
var key = ModelMetadataIdentity.ForProperty(
|
||||||
|
typeof(Person).GetProperty(nameof(Person.Age)),
|
||||||
typeof(int),
|
typeof(int),
|
||||||
nameof(Person.Age),
|
|
||||||
typeof(Person));
|
typeof(Person));
|
||||||
|
|
||||||
var context = new BindingMetadataProviderContext(key, new ModelAttributes(new object[0], new object[0], null));
|
var context = new BindingMetadataProviderContext(key, new ModelAttributes(new object[0], new object[0], null));
|
||||||
|
|
@ -40,8 +40,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
||||||
var provider = new ExcludeBindingMetadataProvider(typeof(int));
|
var provider = new ExcludeBindingMetadataProvider(typeof(int));
|
||||||
|
|
||||||
var key = ModelMetadataIdentity.ForProperty(
|
var key = ModelMetadataIdentity.ForProperty(
|
||||||
|
typeof(Person).GetProperty(nameof(Person.Age)),
|
||||||
typeof(int),
|
typeof(int),
|
||||||
nameof(Person.Age),
|
|
||||||
typeof(Person));
|
typeof(Person));
|
||||||
|
|
||||||
var context = new BindingMetadataProviderContext(key, new ModelAttributes(new object[0], new object[0], null));
|
var context = new BindingMetadataProviderContext(key, new ModelAttributes(new object[0], new object[0], null));
|
||||||
|
|
|
||||||
|
|
@ -365,12 +365,29 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations
|
||||||
// Do nothing.
|
// Do nothing.
|
||||||
}
|
}
|
||||||
else if (context.Key.MetadataKind == ModelMetadataKind.Property)
|
else if (context.Key.MetadataKind == ModelMetadataKind.Property)
|
||||||
|
{
|
||||||
|
var property = context.Key.PropertyInfo;
|
||||||
|
if (property is null)
|
||||||
|
{
|
||||||
|
// PropertyInfo was unavailable on ModelIdentity prior to 3.1.
|
||||||
|
// Making a cogent argument about the nullability of the property requires inspecting the declared type,
|
||||||
|
// since looking at the runtime type may result in false positives: https://github.com/aspnet/AspNetCore/issues/14812
|
||||||
|
// The only way we could arrive here is if the ModelMetadata was constructed using the non-default provider.
|
||||||
|
// We'll cursorily examine the attributes on the property, but not the ContainerType to make a decision about it's nullability.
|
||||||
|
|
||||||
|
if (HasNullableAttribute(context.PropertyAttributes, out var propertyHasNullableAttribute))
|
||||||
|
{
|
||||||
|
addInferredRequiredAttribute = propertyHasNullableAttribute;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
addInferredRequiredAttribute = IsNullableReferenceType(
|
addInferredRequiredAttribute = IsNullableReferenceType(
|
||||||
context.Key.ContainerType,
|
property.DeclaringType,
|
||||||
member: null,
|
member: null,
|
||||||
context.PropertyAttributes);
|
context.PropertyAttributes);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else if (context.Key.MetadataKind == ModelMetadataKind.Parameter)
|
else if (context.Key.MetadataKind == ModelMetadataKind.Parameter)
|
||||||
{
|
{
|
||||||
addInferredRequiredAttribute = IsNullableReferenceType(
|
addInferredRequiredAttribute = IsNullableReferenceType(
|
||||||
|
|
|
||||||
|
|
@ -1111,7 +1111,8 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations
|
||||||
var required = new RequiredAttribute();
|
var required = new RequiredAttribute();
|
||||||
|
|
||||||
var attributes = new Attribute[] { required };
|
var attributes = new Attribute[] { required };
|
||||||
var key = ModelMetadataIdentity.ForProperty(typeof(int), "Length", typeof(string));
|
var property = typeof(string).GetProperty(nameof(string.Length));
|
||||||
|
var key = ModelMetadataIdentity.ForProperty(property, typeof(int), typeof(string));
|
||||||
var context = new ValidationMetadataProviderContext(key, GetModelAttributes(new object[0], attributes));
|
var context = new ValidationMetadataProviderContext(key, GetModelAttributes(new object[0], attributes));
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -1131,7 +1132,8 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations
|
||||||
var provider = CreateProvider();
|
var provider = CreateProvider();
|
||||||
|
|
||||||
var attributes = new Attribute[] { };
|
var attributes = new Attribute[] { };
|
||||||
var key = ModelMetadataIdentity.ForProperty(typeof(int), "Length", typeof(string));
|
var property = typeof(string).GetProperty(nameof(string.Length));
|
||||||
|
var key = ModelMetadataIdentity.ForProperty(property, typeof(int), typeof(string));
|
||||||
var context = new ValidationMetadataProviderContext(key, GetModelAttributes(new object[0], attributes));
|
var context = new ValidationMetadataProviderContext(key, GetModelAttributes(new object[0], attributes));
|
||||||
context.ValidationMetadata.IsRequired = initialValue;
|
context.ValidationMetadata.IsRequired = initialValue;
|
||||||
|
|
||||||
|
|
@ -1152,8 +1154,9 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations
|
||||||
typeof(NullableReferenceTypes),
|
typeof(NullableReferenceTypes),
|
||||||
typeof(NullableReferenceTypes).GetProperty(nameof(NullableReferenceTypes.NonNullableReferenceType)));
|
typeof(NullableReferenceTypes).GetProperty(nameof(NullableReferenceTypes.NonNullableReferenceType)));
|
||||||
var key = ModelMetadataIdentity.ForProperty(
|
var key = ModelMetadataIdentity.ForProperty(
|
||||||
typeof(NullableReferenceTypes),
|
typeof(NullableReferenceTypes).GetProperty(nameof(NullableReferenceTypes.NonNullableReferenceType)),
|
||||||
nameof(NullableReferenceTypes.NonNullableReferenceType), typeof(string));
|
typeof(string),
|
||||||
|
typeof(NullableReferenceTypes));
|
||||||
var context = new ValidationMetadataProviderContext(key, attributes);
|
var context = new ValidationMetadataProviderContext(key, attributes);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -1174,9 +1177,11 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations
|
||||||
var attributes = ModelAttributes.GetAttributesForProperty(
|
var attributes = ModelAttributes.GetAttributesForProperty(
|
||||||
typeof(NullableReferenceTypes),
|
typeof(NullableReferenceTypes),
|
||||||
typeof(NullableReferenceTypes).GetProperty(nameof(NullableReferenceTypes.NonNullableReferenceTypeWithRequired)));
|
typeof(NullableReferenceTypes).GetProperty(nameof(NullableReferenceTypes.NonNullableReferenceTypeWithRequired)));
|
||||||
|
|
||||||
var key = ModelMetadataIdentity.ForProperty(
|
var key = ModelMetadataIdentity.ForProperty(
|
||||||
typeof(NullableReferenceTypes),
|
typeof(NullableReferenceTypes).GetProperty(nameof(NullableReferenceTypes.NonNullableReferenceTypeWithRequired)),
|
||||||
nameof(NullableReferenceTypes.NonNullableReferenceTypeWithRequired), typeof(string));
|
typeof(string),
|
||||||
|
typeof(NullableReferenceTypes));
|
||||||
var context = new ValidationMetadataProviderContext(key, attributes);
|
var context = new ValidationMetadataProviderContext(key, attributes);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -1201,9 +1206,12 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations
|
||||||
var attributes = ModelAttributes.GetAttributesForProperty(
|
var attributes = ModelAttributes.GetAttributesForProperty(
|
||||||
typeof(NullableReferenceTypes),
|
typeof(NullableReferenceTypes),
|
||||||
typeof(NullableReferenceTypes).GetProperty(nameof(NullableReferenceTypes.NonNullableReferenceType)));
|
typeof(NullableReferenceTypes).GetProperty(nameof(NullableReferenceTypes.NonNullableReferenceType)));
|
||||||
|
|
||||||
var key = ModelMetadataIdentity.ForProperty(
|
var key = ModelMetadataIdentity.ForProperty(
|
||||||
typeof(NullableReferenceTypes),
|
typeof(NullableReferenceTypes).GetProperty(nameof(NullableReferenceTypes.NonNullableReferenceType)),
|
||||||
nameof(NullableReferenceTypes.NonNullableReferenceType), typeof(string));
|
typeof(string),
|
||||||
|
typeof(NullableReferenceTypes));
|
||||||
|
|
||||||
var context = new ValidationMetadataProviderContext(key, attributes);
|
var context = new ValidationMetadataProviderContext(key, attributes);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -1214,6 +1222,189 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations
|
||||||
Assert.DoesNotContain(context.ValidationMetadata.ValidatorMetadata, m => m is RequiredAttribute);
|
Assert.DoesNotContain(context.ValidationMetadata.ValidatorMetadata, m => m is RequiredAttribute);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(nameof(DerivedTypeWithAllNonNullProperties.Property1))]
|
||||||
|
[InlineData(nameof(DerivedTypeWithAllNonNullProperties.Property2))]
|
||||||
|
public void CreateValidationMetadata_InfersRequiredAttributeOnDerivedType_BaseAnDerivedTypHaveAllNonNullProperties(string propertyName)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var provider = CreateProvider();
|
||||||
|
|
||||||
|
var modelType = typeof(DerivedTypeWithAllNonNullProperties);
|
||||||
|
var property = modelType.GetProperty(propertyName);
|
||||||
|
var key = ModelMetadataIdentity.ForProperty(property, property.PropertyType, modelType);
|
||||||
|
var context = new ValidationMetadataProviderContext(key, ModelAttributes.GetAttributesForProperty(modelType, property));
|
||||||
|
|
||||||
|
// This test verifies how MVC reads the NullableContextOptions. We expect the property to not have a Nullable attribute on, and for
|
||||||
|
// the types to have NullableContext. We'll encode our expectations as assertions so that we can catch if or when the compiler changes
|
||||||
|
// this behavior and the test needs to be tweaked.
|
||||||
|
Assert.False(DataAnnotationsMetadataProvider.HasNullableAttribute(context.PropertyAttributes, out _), "We do not expect NullableAttribute to be defined on the property");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
provider.CreateValidationMetadata(context);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.True(context.ValidationMetadata.IsRequired);
|
||||||
|
Assert.Contains(context.ValidationMetadata.ValidatorMetadata, m => m is RequiredAttribute);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void CreateValidationMetadata_InfersRequiredAttributeOnDerivedType_PropertyDeclaredOnBaseType()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var provider = CreateProvider();
|
||||||
|
|
||||||
|
var modelType = typeof(DerivedTypeWithAllNonNullProperties_WithNullableProperties);
|
||||||
|
var property = modelType.GetProperty(nameof(DerivedTypeWithAllNonNullProperties_WithNullableProperties.Property1));
|
||||||
|
var key = ModelMetadataIdentity.ForProperty(property, property.PropertyType, modelType);
|
||||||
|
var context = new ValidationMetadataProviderContext(key, ModelAttributes.GetAttributesForProperty(modelType, property));
|
||||||
|
|
||||||
|
// Act
|
||||||
|
provider.CreateValidationMetadata(context);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.True(context.ValidationMetadata.IsRequired);
|
||||||
|
Assert.Contains(context.ValidationMetadata.ValidatorMetadata, m => m is RequiredAttribute);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void CreateValidationMetadata_InfersRequiredAttributeOnDerivedType_NullablePropertyDeclaredOnDerviedType()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var provider = CreateProvider();
|
||||||
|
|
||||||
|
var modelType = typeof(DerivedTypeWithAllNonNullProperties_WithNullableProperties);
|
||||||
|
var property = modelType.GetProperty(nameof(DerivedTypeWithAllNonNullProperties_WithNullableProperties.Property2));
|
||||||
|
var key = ModelMetadataIdentity.ForProperty(property, property.PropertyType, modelType);
|
||||||
|
var context = new ValidationMetadataProviderContext(key, ModelAttributes.GetAttributesForProperty(modelType, property));
|
||||||
|
|
||||||
|
// Act
|
||||||
|
provider.CreateValidationMetadata(context);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Null(context.ValidationMetadata.IsRequired);
|
||||||
|
Assert.DoesNotContain(context.ValidationMetadata.ValidatorMetadata, m => m is RequiredAttribute);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(nameof(DerivedTypeWithNullableProperties.Property1))]
|
||||||
|
[InlineData(nameof(DerivedTypeWithNullableProperties.Property2))]
|
||||||
|
public void CreateValidationMetadata_BaseAnDerivedTypHaveAllNullableProperties_DoesNotInferRequiredAttribute(string propertyName)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var provider = CreateProvider();
|
||||||
|
|
||||||
|
var modelType = typeof(DerivedTypeWithNullableProperties);
|
||||||
|
var property = modelType.GetProperty(propertyName);
|
||||||
|
var key = ModelMetadataIdentity.ForProperty(property, property.PropertyType, modelType);
|
||||||
|
var context = new ValidationMetadataProviderContext(key, ModelAttributes.GetAttributesForProperty(modelType, property));
|
||||||
|
|
||||||
|
// Act
|
||||||
|
provider.CreateValidationMetadata(context);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Null(context.ValidationMetadata.IsRequired);
|
||||||
|
Assert.DoesNotContain(context.ValidationMetadata.ValidatorMetadata, m => m is RequiredAttribute);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void CreateValidationMetadata_InfersRequiredAttribute_BaseTypeIsNullable_PropertyIsNotNull()
|
||||||
|
{
|
||||||
|
// Tests the scenario listed in https://github.com/aspnet/AspNetCore/issues/14812
|
||||||
|
// Arrange
|
||||||
|
var provider = CreateProvider();
|
||||||
|
|
||||||
|
var modelType = typeof(DerivedTypeWithNullableProperties_WithNonNullProperties);
|
||||||
|
var property = modelType.GetProperty(nameof(DerivedTypeWithNullableProperties_WithNonNullProperties.Property2));
|
||||||
|
var key = ModelMetadataIdentity.ForProperty(property, property.PropertyType, modelType);
|
||||||
|
var context = new ValidationMetadataProviderContext(key, ModelAttributes.GetAttributesForProperty(modelType, property));
|
||||||
|
|
||||||
|
// Act
|
||||||
|
provider.CreateValidationMetadata(context);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.True(context.ValidationMetadata.IsRequired);
|
||||||
|
Assert.Contains(context.ValidationMetadata.ValidatorMetadata, m => m is RequiredAttribute);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void CreateValidationMetadata_InfersRequiredAttribute_ShadowedPropertyIsNonNull()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var provider = CreateProvider();
|
||||||
|
|
||||||
|
var modelType = typeof(DerivedTypeWithNullableProperties_ShadowedProperty);
|
||||||
|
var property = modelType.GetProperty(nameof(DerivedTypeWithNullableProperties_ShadowedProperty.Property1));
|
||||||
|
var key = ModelMetadataIdentity.ForProperty(property, property.PropertyType, modelType);
|
||||||
|
var context = new ValidationMetadataProviderContext(key, ModelAttributes.GetAttributesForProperty(modelType, property));
|
||||||
|
|
||||||
|
// Act
|
||||||
|
provider.CreateValidationMetadata(context);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.True(context.ValidationMetadata.IsRequired);
|
||||||
|
Assert.Contains(context.ValidationMetadata.ValidatorMetadata, m => m is RequiredAttribute);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void CreateValidationMetadata_DoesNotInfersRequiredAttribute_TypeImplementingNonNullAbstractClass()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var provider = CreateProvider();
|
||||||
|
|
||||||
|
var modelType = typeof(TypeImplementIInterfaceWithNonNullProperty);
|
||||||
|
var property = modelType.GetProperty(nameof(TypeImplementIInterfaceWithNonNullProperty.Property));
|
||||||
|
var key = ModelMetadataIdentity.ForProperty(property, property.PropertyType, modelType);
|
||||||
|
var context = new ValidationMetadataProviderContext(key, ModelAttributes.GetAttributesForProperty(modelType, property));
|
||||||
|
|
||||||
|
// Act
|
||||||
|
provider.CreateValidationMetadata(context);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.True(context.ValidationMetadata.IsRequired);
|
||||||
|
Assert.Contains(context.ValidationMetadata.ValidatorMetadata, m => m is RequiredAttribute);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void CreateValidationMetadata_DoesNotInfersRequiredAttribute_TypeImplementingNonNullAbstractClass_NotNullable()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var provider = CreateProvider();
|
||||||
|
|
||||||
|
var modelType = typeof(TypeImplementIInterfaceWithNonNullProperty_AsNullable);
|
||||||
|
var property = modelType.GetProperty(nameof(TypeImplementIInterfaceWithNonNullProperty_AsNullable.Property));
|
||||||
|
var key = ModelMetadataIdentity.ForProperty(property, property.PropertyType, modelType);
|
||||||
|
var context = new ValidationMetadataProviderContext(key, ModelAttributes.GetAttributesForProperty(modelType, property));
|
||||||
|
|
||||||
|
// Act
|
||||||
|
provider.CreateValidationMetadata(context);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Null(context.ValidationMetadata.IsRequired);
|
||||||
|
Assert.DoesNotContain(context.ValidationMetadata.ValidatorMetadata, m => m is RequiredAttribute);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void CreateValidationMetadata_WithOldModelIdentity_DoesNotInferValueBasedOnContext()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var provider = CreateProvider();
|
||||||
|
|
||||||
|
var modelType = typeof(TypeWithAllNonNullProperties);
|
||||||
|
var property = modelType.GetProperty(nameof(TypeWithAllNonNullProperties.Property1));
|
||||||
|
#pragma warning disable CS0618 // Type or member is obsolete
|
||||||
|
var key = ModelMetadataIdentity.ForProperty(property.PropertyType, property.Name, modelType);
|
||||||
|
#pragma warning restore CS0618 // Type or member is obsolete
|
||||||
|
var context = new ValidationMetadataProviderContext(key, ModelAttributes.GetAttributesForProperty(modelType, property));
|
||||||
|
|
||||||
|
// Act
|
||||||
|
provider.CreateValidationMetadata(context);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Null(context.ValidationMetadata.IsRequired);
|
||||||
|
Assert.DoesNotContain(context.ValidationMetadata.ValidatorMetadata, m => m is RequiredAttribute);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void CreateValidationMetadata_WillAddValidationAttributes_From_ValidationProviderAttribute()
|
public void CreateValidationMetadata_WillAddValidationAttributes_From_ValidationProviderAttribute()
|
||||||
{
|
{
|
||||||
|
|
@ -1227,7 +1418,8 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations
|
||||||
});
|
});
|
||||||
|
|
||||||
var attributes = new Attribute[] { new EmailAddressAttribute(), validationProviderAttribute };
|
var attributes = new Attribute[] { new EmailAddressAttribute(), validationProviderAttribute };
|
||||||
var key = ModelMetadataIdentity.ForProperty(typeof(string), "Length", typeof(string));
|
var property = typeof(string).GetProperty(nameof(string.Length));
|
||||||
|
var key = ModelMetadataIdentity.ForProperty(property, typeof(int), typeof(string));
|
||||||
var context = new ValidationMetadataProviderContext(key, GetModelAttributes(new object[0], attributes));
|
var context = new ValidationMetadataProviderContext(key, GetModelAttributes(new object[0], attributes));
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -1254,7 +1446,8 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations
|
||||||
var provider = CreateProvider();
|
var provider = CreateProvider();
|
||||||
|
|
||||||
var attributes = new Attribute[] { new RequiredAttribute() };
|
var attributes = new Attribute[] { new RequiredAttribute() };
|
||||||
var key = ModelMetadataIdentity.ForProperty(typeof(int), "Length", typeof(string));
|
var property = typeof(string).GetProperty(nameof(string.Length));
|
||||||
|
var key = ModelMetadataIdentity.ForProperty(property, typeof(int), typeof(string));
|
||||||
var context = new BindingMetadataProviderContext(key, GetModelAttributes(new object[0], attributes));
|
var context = new BindingMetadataProviderContext(key, GetModelAttributes(new object[0], attributes));
|
||||||
context.BindingMetadata.IsBindingRequired = initialValue;
|
context.BindingMetadata.IsBindingRequired = initialValue;
|
||||||
|
|
||||||
|
|
@ -1275,7 +1468,8 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations
|
||||||
var provider = CreateProvider();
|
var provider = CreateProvider();
|
||||||
|
|
||||||
var attributes = new Attribute[] { };
|
var attributes = new Attribute[] { };
|
||||||
var key = ModelMetadataIdentity.ForProperty(typeof(int), "Length", typeof(string));
|
var property = typeof(string).GetProperty(nameof(string.Length));
|
||||||
|
var key = ModelMetadataIdentity.ForProperty(property, typeof(int), typeof(string));
|
||||||
var context = new BindingMetadataProviderContext(key, GetModelAttributes(new object[0], attributes));
|
var context = new BindingMetadataProviderContext(key, GetModelAttributes(new object[0], attributes));
|
||||||
context.BindingMetadata.IsReadOnly = initialValue;
|
context.BindingMetadata.IsReadOnly = initialValue;
|
||||||
|
|
||||||
|
|
@ -1294,7 +1488,8 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations
|
||||||
|
|
||||||
var attribute = new TestValidationAttribute();
|
var attribute = new TestValidationAttribute();
|
||||||
var attributes = new Attribute[] { attribute };
|
var attributes = new Attribute[] { attribute };
|
||||||
var key = ModelMetadataIdentity.ForProperty(typeof(int), "Length", typeof(string));
|
var property = typeof(string).GetProperty(nameof(string.Length));
|
||||||
|
var key = ModelMetadataIdentity.ForProperty(property, typeof(int), typeof(string));
|
||||||
var context = new ValidationMetadataProviderContext(key, GetModelAttributes(new object[0], attributes));
|
var context = new ValidationMetadataProviderContext(key, GetModelAttributes(new object[0], attributes));
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -1313,7 +1508,29 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations
|
||||||
|
|
||||||
var attribute = new TestValidationAttribute();
|
var attribute = new TestValidationAttribute();
|
||||||
var attributes = new Attribute[] { attribute };
|
var attributes = new Attribute[] { attribute };
|
||||||
var key = ModelMetadataIdentity.ForProperty(typeof(int), "Length", typeof(string));
|
var property = typeof(string).GetProperty(nameof(string.Length));
|
||||||
|
var key = ModelMetadataIdentity.ForProperty(property, typeof(int), typeof(string));
|
||||||
|
var context = new ValidationMetadataProviderContext(key, GetModelAttributes(new object[0], attributes));
|
||||||
|
context.ValidationMetadata.ValidatorMetadata.Add(attribute);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
provider.CreateValidationMetadata(context);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var validatorMetadata = Assert.Single(context.ValidationMetadata.ValidatorMetadata);
|
||||||
|
Assert.Same(attribute, validatorMetadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void CreateValidationDetails_ForProperty()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var provider = CreateProvider();
|
||||||
|
|
||||||
|
var attribute = new TestValidationAttribute();
|
||||||
|
var attributes = new Attribute[] { attribute };
|
||||||
|
var property = typeof(string).GetProperty(nameof(string.Length));
|
||||||
|
var key = ModelMetadataIdentity.ForProperty(property, typeof(int), typeof(string));
|
||||||
var context = new ValidationMetadataProviderContext(key, GetModelAttributes(new object[0], attributes));
|
var context = new ValidationMetadataProviderContext(key, GetModelAttributes(new object[0], attributes));
|
||||||
context.ValidationMetadata.ValidatorMetadata.Add(attribute);
|
context.ValidationMetadata.ValidatorMetadata.Add(attribute);
|
||||||
|
|
||||||
|
|
@ -1657,6 +1874,56 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class TypeWithAllNonNullProperties
|
||||||
|
{
|
||||||
|
public string Property1 { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class DerivedTypeWithAllNonNullProperties : TypeWithAllNonNullProperties
|
||||||
|
{
|
||||||
|
public string Property2 { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class DerivedTypeWithAllNonNullProperties_WithNullableProperties : TypeWithAllNonNullProperties
|
||||||
|
{
|
||||||
|
public string? Property2 { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TypeWithNullableProperties
|
||||||
|
{
|
||||||
|
public string? Property1 { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private class DerivedTypeWithNullableProperties : TypeWithNullableProperties
|
||||||
|
{
|
||||||
|
public string? Property2 { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private class DerivedTypeWithNullableProperties_WithNonNullProperties : TypeWithNullableProperties
|
||||||
|
{
|
||||||
|
public string Property2 { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class DerivedTypeWithNullableProperties_ShadowedProperty : TypeWithNullableProperties
|
||||||
|
{
|
||||||
|
public new string Property1 { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract class AbstraceTypehNonNullProperty
|
||||||
|
{
|
||||||
|
public abstract string Property { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TypeImplementIInterfaceWithNonNullProperty : AbstraceTypehNonNullProperty
|
||||||
|
{
|
||||||
|
public override string Property { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
#nullable restore
|
#nullable restore
|
||||||
|
|
||||||
|
public class TypeImplementIInterfaceWithNonNullProperty_AsNullable : AbstraceTypehNonNullProperty
|
||||||
|
{
|
||||||
|
public override string Property { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,8 +24,8 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations
|
||||||
};
|
};
|
||||||
|
|
||||||
var key = ModelMetadataIdentity.ForProperty(
|
var key = ModelMetadataIdentity.ForProperty(
|
||||||
|
typeof(ClassWithDataMemberIsRequiredTrue).GetProperty(nameof(ClassWithDataMemberIsRequiredTrue.StringProperty)),
|
||||||
typeof(string),
|
typeof(string),
|
||||||
nameof(ClassWithDataMemberIsRequiredTrue.StringProperty),
|
|
||||||
typeof(ClassWithDataMemberIsRequiredTrue));
|
typeof(ClassWithDataMemberIsRequiredTrue));
|
||||||
var context = new BindingMetadataProviderContext(key, GetModelAttributes(new object[0], attributes));
|
var context = new BindingMetadataProviderContext(key, GetModelAttributes(new object[0], attributes));
|
||||||
|
|
||||||
|
|
@ -50,8 +50,8 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations
|
||||||
};
|
};
|
||||||
|
|
||||||
var key = ModelMetadataIdentity.ForProperty(
|
var key = ModelMetadataIdentity.ForProperty(
|
||||||
|
typeof(ClassWithDataMemberIsRequiredFalse).GetProperty(nameof(ClassWithDataMemberIsRequiredFalse.StringProperty)),
|
||||||
typeof(string),
|
typeof(string),
|
||||||
nameof(ClassWithDataMemberIsRequiredFalse.StringProperty),
|
|
||||||
typeof(ClassWithDataMemberIsRequiredFalse));
|
typeof(ClassWithDataMemberIsRequiredFalse));
|
||||||
var context = new BindingMetadataProviderContext(key, GetModelAttributes(new object[0], attributes));
|
var context = new BindingMetadataProviderContext(key, GetModelAttributes(new object[0], attributes));
|
||||||
|
|
||||||
|
|
@ -98,8 +98,8 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations
|
||||||
var provider = new DataMemberRequiredBindingMetadataProvider();
|
var provider = new DataMemberRequiredBindingMetadataProvider();
|
||||||
|
|
||||||
var key = ModelMetadataIdentity.ForProperty(
|
var key = ModelMetadataIdentity.ForProperty(
|
||||||
|
typeof(ClassWithoutAttributes).GetProperty(nameof(ClassWithoutAttributes.StringProperty)),
|
||||||
typeof(string),
|
typeof(string),
|
||||||
nameof(ClassWithoutAttributes.StringProperty),
|
|
||||||
typeof(ClassWithoutAttributes));
|
typeof(ClassWithoutAttributes));
|
||||||
var context = new BindingMetadataProviderContext(key, GetModelAttributes(new object[0], new object[0]));
|
var context = new BindingMetadataProviderContext(key, GetModelAttributes(new object[0], new object[0]));
|
||||||
|
|
||||||
|
|
@ -126,8 +126,8 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations
|
||||||
};
|
};
|
||||||
|
|
||||||
var key = ModelMetadataIdentity.ForProperty(
|
var key = ModelMetadataIdentity.ForProperty(
|
||||||
|
typeof(ClassWithDataMemberIsRequiredTrueWithoutDataContract).GetProperty(nameof(ClassWithDataMemberIsRequiredTrueWithoutDataContract.StringProperty)),
|
||||||
typeof(string),
|
typeof(string),
|
||||||
nameof(ClassWithDataMemberIsRequiredTrueWithoutDataContract.StringProperty),
|
|
||||||
typeof(ClassWithDataMemberIsRequiredTrueWithoutDataContract));
|
typeof(ClassWithDataMemberIsRequiredTrueWithoutDataContract));
|
||||||
var context = new BindingMetadataProviderContext(key, GetModelAttributes(new object[0], attributes));
|
var context = new BindingMetadataProviderContext(key, GetModelAttributes(new object[0], attributes));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -196,8 +196,15 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(exception is JsonException || exception is OverflowException))
|
if (!(exception is JsonException || exception is OverflowException || exception is FormatException))
|
||||||
{
|
{
|
||||||
|
// At this point we've already recorded all exceptions as an entry in the ModelStateDictionary.
|
||||||
|
// We only need to rethrow an exception if we believe it needs to be handled by something further up
|
||||||
|
// the stack.
|
||||||
|
// JsonException, OverflowException, and FormatException are assumed to be only encountered when
|
||||||
|
// parsing the JSON and are consequently "safe" to be exposed as part of ModelState. Everything else
|
||||||
|
// needs to be rethrown.
|
||||||
|
|
||||||
var exceptionDispatchInfo = ExceptionDispatchInfo.Capture(exception);
|
var exceptionDispatchInfo = ExceptionDispatchInfo.Capture(exception);
|
||||||
exceptionDispatchInfo.Throw();
|
exceptionDispatchInfo.Throw();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ using Microsoft.Extensions.Logging.Abstractions;
|
||||||
using Microsoft.Extensions.ObjectPool;
|
using Microsoft.Extensions.ObjectPool;
|
||||||
using Moq;
|
using Moq;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Converters;
|
||||||
using Newtonsoft.Json.Serialization;
|
using Newtonsoft.Json.Serialization;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
|
|
@ -21,8 +22,8 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
{
|
{
|
||||||
public class NewtonsoftJsonInputFormatterTest : JsonInputFormatterTestBase
|
public class NewtonsoftJsonInputFormatterTest : JsonInputFormatterTestBase
|
||||||
{
|
{
|
||||||
private static readonly ObjectPoolProvider _objectPoolProvider = new DefaultObjectPoolProvider();
|
private readonly ObjectPoolProvider _objectPoolProvider = new DefaultObjectPoolProvider();
|
||||||
private static readonly JsonSerializerSettings _serializerSettings = new JsonSerializerSettings();
|
private readonly JsonSerializerSettings _serializerSettings = new JsonSerializerSettings();
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task Constructor_BuffersRequestBody_UsingDefaultOptions()
|
public async Task Constructor_BuffersRequestBody_UsingDefaultOptions()
|
||||||
|
|
@ -144,7 +145,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
var serializerSettings = new JsonSerializerSettings();
|
var serializerSettings = new JsonSerializerSettings();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var formatter = new TestableJsonInputFormatter(serializerSettings);
|
var formatter = new TestableJsonInputFormatter(serializerSettings, _objectPoolProvider);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Same(serializerSettings, formatter.SerializerSettings);
|
Assert.Same(serializerSettings, formatter.SerializerSettings);
|
||||||
|
|
@ -185,7 +186,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
MaxDepth = 2,
|
MaxDepth = 2,
|
||||||
DateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind,
|
DateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind,
|
||||||
};
|
};
|
||||||
var formatter = new TestableJsonInputFormatter(settings);
|
var formatter = new TestableJsonInputFormatter(settings, _objectPoolProvider);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var actual = formatter.CreateJsonSerializer(null);
|
var actual = formatter.CreateJsonSerializer(null);
|
||||||
|
|
@ -304,7 +305,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task ReadAsync_lowInputFormatterExceptionMessages_DoesNotWrapJsonInputExceptions()
|
public async Task ReadAsync_AllowInputFormatterExceptionMessages_DoesNotWrapJsonInputExceptions()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var formatter = new NewtonsoftJsonInputFormatter(
|
var formatter = new NewtonsoftJsonInputFormatter(
|
||||||
|
|
@ -336,10 +337,72 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
Assert.NotEmpty(modelError.ErrorMessage);
|
Assert.NotEmpty(modelError.ErrorMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task ReadAsync_DoesNotRethrowFormatExceptions()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
_serializerSettings.Converters.Add(new IsoDateTimeConverter());
|
||||||
|
|
||||||
|
var formatter = new NewtonsoftJsonInputFormatter(
|
||||||
|
GetLogger(),
|
||||||
|
_serializerSettings,
|
||||||
|
ArrayPool<char>.Shared,
|
||||||
|
_objectPoolProvider,
|
||||||
|
new MvcOptions(),
|
||||||
|
new MvcNewtonsoftJsonOptions());
|
||||||
|
|
||||||
|
var contentBytes = Encoding.UTF8.GetBytes("{\"dateValue\":\"not-a-date\"}");
|
||||||
|
var httpContext = GetHttpContext(contentBytes);
|
||||||
|
|
||||||
|
var formatterContext = CreateInputFormatterContext(typeof(TypeWithPrimitives), httpContext);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = await formatter.ReadAsync(formatterContext);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.True(result.HasError);
|
||||||
|
Assert.False(formatterContext.ModelState.IsValid);
|
||||||
|
|
||||||
|
var modelError = Assert.Single(formatterContext.ModelState["dateValue"].Errors);
|
||||||
|
Assert.Null(modelError.Exception);
|
||||||
|
Assert.Equal("The supplied value is invalid.", modelError.ErrorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task ReadAsync_DoesNotRethrowOverflowExceptions()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
_serializerSettings.Converters.Add(new IsoDateTimeConverter());
|
||||||
|
|
||||||
|
var formatter = new NewtonsoftJsonInputFormatter(
|
||||||
|
GetLogger(),
|
||||||
|
_serializerSettings,
|
||||||
|
ArrayPool<char>.Shared,
|
||||||
|
_objectPoolProvider,
|
||||||
|
new MvcOptions(),
|
||||||
|
new MvcNewtonsoftJsonOptions());
|
||||||
|
|
||||||
|
var contentBytes = Encoding.UTF8.GetBytes("{\"shortValue\":\"32768\"}");
|
||||||
|
var httpContext = GetHttpContext(contentBytes);
|
||||||
|
|
||||||
|
var formatterContext = CreateInputFormatterContext(typeof(TypeWithPrimitives), httpContext);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = await formatter.ReadAsync(formatterContext);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.True(result.HasError);
|
||||||
|
Assert.False(formatterContext.ModelState.IsValid);
|
||||||
|
|
||||||
|
var modelError = Assert.Single(formatterContext.ModelState["shortValue"].Errors);
|
||||||
|
Assert.Null(modelError.Exception);
|
||||||
|
Assert.Equal("The supplied value is invalid.", modelError.ErrorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
private class TestableJsonInputFormatter : NewtonsoftJsonInputFormatter
|
private class TestableJsonInputFormatter : NewtonsoftJsonInputFormatter
|
||||||
{
|
{
|
||||||
public TestableJsonInputFormatter(JsonSerializerSettings settings)
|
public TestableJsonInputFormatter(JsonSerializerSettings settings, ObjectPoolProvider objectPoolProvider)
|
||||||
: base(GetLogger(), settings, ArrayPool<char>.Shared, _objectPoolProvider, new MvcOptions(), new MvcNewtonsoftJsonOptions())
|
: base(GetLogger(), settings, ArrayPool<char>.Shared, objectPoolProvider, new MvcOptions(), new MvcNewtonsoftJsonOptions())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -418,5 +481,26 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
[JsonProperty(Required = Required.Always)]
|
[JsonProperty(Required = Required.Always)]
|
||||||
public string Password { get; set; }
|
public string Password { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class TypeWithPrimitives
|
||||||
|
{
|
||||||
|
public DateTime DateValue { get; set; }
|
||||||
|
|
||||||
|
[JsonConverter(typeof(IncorrectShortConverter))]
|
||||||
|
public short ShortValue { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private class IncorrectShortConverter : JsonConverter<short>
|
||||||
|
{
|
||||||
|
public override short ReadJson(JsonReader reader, Type objectType, short existingValue, bool hasExistingValue, JsonSerializer serializer)
|
||||||
|
{
|
||||||
|
return short.Parse(reader.Value.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void WriteJson(JsonWriter writer, short value, JsonSerializer serializer)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -122,7 +122,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
||||||
var property = containerType.GetRuntimeProperty(propertyName);
|
var property = containerType.GetRuntimeProperty(propertyName);
|
||||||
Assert.NotNull(property);
|
Assert.NotNull(property);
|
||||||
|
|
||||||
var key = ModelMetadataIdentity.ForProperty(property.PropertyType, propertyName, containerType);
|
var key = ModelMetadataIdentity.ForProperty(property, property.PropertyType, containerType);
|
||||||
|
|
||||||
var builder = new MetadataBuilder(key);
|
var builder = new MetadataBuilder(key);
|
||||||
_detailsProvider.Builders.Add(builder);
|
_detailsProvider.Builders.Add(builder);
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="main">
|
<div class="main">
|
||||||
<div class="top-row px-4">
|
<div class="top-row px-4 auth">
|
||||||
<LoginDisplay />
|
<LoginDisplay />
|
||||||
<a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a>
|
<a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
{
|
{
|
||||||
|
"DetailedErrors": true,
|
||||||
"Logging": {
|
"Logging": {
|
||||||
"LogLevel": {
|
"LogLevel": {
|
||||||
"Default": "Information",
|
"Default": "Information",
|
||||||
|
|
|
||||||
|
|
@ -36,10 +36,16 @@ app {
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
}
|
}
|
||||||
|
|
||||||
.main .top-row > a {
|
.main .top-row > a, .main .top-row .btn-link {
|
||||||
|
white-space: nowrap;
|
||||||
margin-left: 1.5rem;
|
margin-left: 1.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.main .top-row a:first-child {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
.sidebar {
|
.sidebar {
|
||||||
background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%);
|
background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%);
|
||||||
}
|
}
|
||||||
|
|
@ -59,20 +65,20 @@ app {
|
||||||
top: -2px;
|
top: -2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-item {
|
.sidebar .nav-item {
|
||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
padding-bottom: 0.5rem;
|
padding-bottom: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-item:first-of-type {
|
.sidebar .nav-item:first-of-type {
|
||||||
padding-top: 1rem;
|
padding-top: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-item:last-of-type {
|
.sidebar .nav-item:last-of-type {
|
||||||
padding-bottom: 1rem;
|
padding-bottom: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-item a {
|
.sidebar .nav-item a {
|
||||||
color: #d7d7d7;
|
color: #d7d7d7;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
height: 3rem;
|
height: 3rem;
|
||||||
|
|
@ -81,12 +87,12 @@ app {
|
||||||
line-height: 3rem;
|
line-height: 3rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-item a.active {
|
.sidebar .nav-item a.active {
|
||||||
background-color: rgba(255,255,255,0.25);
|
background-color: rgba(255,255,255,0.25);
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-item a:hover {
|
.sidebar .nav-item a:hover {
|
||||||
background-color: rgba(255,255,255,0.1);
|
background-color: rgba(255,255,255,0.1);
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
@ -131,9 +137,17 @@ app {
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 767.98px) {
|
@media (max-width: 767.98px) {
|
||||||
.main .top-row {
|
.main .top-row:not(.auth) {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.main .top-row.auth {
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main .top-row a, .main .top-row .btn-link {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width: 768px) {
|
@media (min-width: 768px) {
|
||||||
|
|
|
||||||
|
|
@ -10,10 +10,10 @@ namespace Microsoft.AspNetCore.Authentication.Facebook
|
||||||
public static readonly string DisplayName = "Facebook";
|
public static readonly string DisplayName = "Facebook";
|
||||||
|
|
||||||
// https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow#login
|
// https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow#login
|
||||||
public static readonly string AuthorizationEndpoint = "https://www.facebook.com/v3.3/dialog/oauth";
|
public static readonly string AuthorizationEndpoint = "https://www.facebook.com/v4.0/dialog/oauth";
|
||||||
|
|
||||||
public static readonly string TokenEndpoint = "https://graph.facebook.com/v3.3/oauth/access_token";
|
public static readonly string TokenEndpoint = "https://graph.facebook.com/v4.0/oauth/access_token";
|
||||||
|
|
||||||
public static readonly string UserInformationEndpoint = "https://graph.facebook.com/v3.3/me";
|
public static readonly string UserInformationEndpoint = "https://graph.facebook.com/v4.0/me";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -225,7 +225,7 @@ namespace Microsoft.AspNetCore.Authentication.Facebook
|
||||||
var transaction = await server.SendAsync("http://example.com/base/login");
|
var transaction = await server.SendAsync("http://example.com/base/login");
|
||||||
Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode);
|
Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode);
|
||||||
var location = transaction.Response.Headers.Location.AbsoluteUri;
|
var location = transaction.Response.Headers.Location.AbsoluteUri;
|
||||||
Assert.Contains("https://www.facebook.com/v3.3/dialog/oauth", location);
|
Assert.Contains("https://www.facebook.com/v4.0/dialog/oauth", location);
|
||||||
Assert.Contains("response_type=code", location);
|
Assert.Contains("response_type=code", location);
|
||||||
Assert.Contains("client_id=", location);
|
Assert.Contains("client_id=", location);
|
||||||
Assert.Contains("redirect_uri=" + UrlEncoder.Default.Encode("http://example.com/base/signin-facebook"), location);
|
Assert.Contains("redirect_uri=" + UrlEncoder.Default.Encode("http://example.com/base/signin-facebook"), location);
|
||||||
|
|
@ -257,7 +257,7 @@ namespace Microsoft.AspNetCore.Authentication.Facebook
|
||||||
var transaction = await server.SendAsync("http://example.com/login");
|
var transaction = await server.SendAsync("http://example.com/login");
|
||||||
Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode);
|
Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode);
|
||||||
var location = transaction.Response.Headers.Location.AbsoluteUri;
|
var location = transaction.Response.Headers.Location.AbsoluteUri;
|
||||||
Assert.Contains("https://www.facebook.com/v3.3/dialog/oauth", location);
|
Assert.Contains("https://www.facebook.com/v4.0/dialog/oauth", location);
|
||||||
Assert.Contains("response_type=code", location);
|
Assert.Contains("response_type=code", location);
|
||||||
Assert.Contains("client_id=", location);
|
Assert.Contains("client_id=", location);
|
||||||
Assert.Contains("redirect_uri=" + UrlEncoder.Default.Encode("http://example.com/signin-facebook"), location);
|
Assert.Contains("redirect_uri=" + UrlEncoder.Default.Encode("http://example.com/signin-facebook"), location);
|
||||||
|
|
@ -291,7 +291,7 @@ namespace Microsoft.AspNetCore.Authentication.Facebook
|
||||||
var transaction = await server.SendAsync("http://example.com/challenge");
|
var transaction = await server.SendAsync("http://example.com/challenge");
|
||||||
Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode);
|
Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode);
|
||||||
var location = transaction.Response.Headers.Location.AbsoluteUri;
|
var location = transaction.Response.Headers.Location.AbsoluteUri;
|
||||||
Assert.Contains("https://www.facebook.com/v3.3/dialog/oauth", location);
|
Assert.Contains("https://www.facebook.com/v4.0/dialog/oauth", location);
|
||||||
Assert.Contains("response_type=code", location);
|
Assert.Contains("response_type=code", location);
|
||||||
Assert.Contains("client_id=", location);
|
Assert.Contains("client_id=", location);
|
||||||
Assert.Contains("redirect_uri=", location);
|
Assert.Contains("redirect_uri=", location);
|
||||||
|
|
|
||||||
|
|
@ -76,9 +76,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
Assert.False(https);
|
Assert.False(https);
|
||||||
}
|
}
|
||||||
|
|
||||||
[OSSkipCondition(OperatingSystems.Windows, WindowsVersions.Win7, WindowsVersions.Win8, WindowsVersions.Win81, WindowsVersions.Win2008R2, SkipReason = "UnixDomainSocketEndPoint is not supported on older versions of Windows")]
|
|
||||||
[SkipOnHelix("https://github.com/aspnet/AspNetCore/issues/14382", Queues = "Windows.10.Amd64.Open")]
|
[SkipOnHelix("https://github.com/aspnet/AspNetCore/issues/14382", Queues = "Windows.10.Amd64.Open")]
|
||||||
[ConditionalFact]
|
[ConditionalFact]
|
||||||
|
[MinimumOSVersion(OperatingSystems.Windows, WindowsVersions.Win10_RS4)]
|
||||||
public void ParseAddressUnixPipe()
|
public void ParseAddressUnixPipe()
|
||||||
{
|
{
|
||||||
var listenOptions = AddressBinder.ParseAddress("http://unix:/tmp/kestrel-test.sock", out var https);
|
var listenOptions = AddressBinder.ParseAddress("http://unix:/tmp/kestrel-test.sock", out var https);
|
||||||
|
|
|
||||||
|
|
@ -320,7 +320,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Tests
|
||||||
// [InlineData("http2", HttpProtocols.Http2)] // Not supported due to missing ALPN support. https://github.com/dotnet/corefx/issues/33016
|
// [InlineData("http2", HttpProtocols.Http2)] // Not supported due to missing ALPN support. https://github.com/dotnet/corefx/issues/33016
|
||||||
[InlineData("http1AndHttp2", HttpProtocols.Http1AndHttp2)] // Gracefully falls back to HTTP/1
|
[InlineData("http1AndHttp2", HttpProtocols.Http1AndHttp2)] // Gracefully falls back to HTTP/1
|
||||||
[OSSkipCondition(OperatingSystems.Linux)]
|
[OSSkipCondition(OperatingSystems.Linux)]
|
||||||
[OSSkipCondition(OperatingSystems.Windows, WindowsVersions.Win10, WindowsVersions.Win8, WindowsVersions.Win81)]
|
[OSSkipCondition(OperatingSystems.Windows, WindowsVersions.Win10, WindowsVersions.Win81)]
|
||||||
public void DefaultConfigSectionCanSetProtocols_MacAndWin7(string input, HttpProtocols expected)
|
public void DefaultConfigSectionCanSetProtocols_MacAndWin7(string input, HttpProtocols expected)
|
||||||
=> DefaultConfigSectionCanSetProtocols(input, expected);
|
=> DefaultConfigSectionCanSetProtocols(input, expected);
|
||||||
|
|
||||||
|
|
@ -329,7 +329,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Tests
|
||||||
[InlineData("http2", HttpProtocols.Http2)]
|
[InlineData("http2", HttpProtocols.Http2)]
|
||||||
[InlineData("http1AndHttp2", HttpProtocols.Http1AndHttp2)]
|
[InlineData("http1AndHttp2", HttpProtocols.Http1AndHttp2)]
|
||||||
[OSSkipCondition(OperatingSystems.MacOSX)]
|
[OSSkipCondition(OperatingSystems.MacOSX)]
|
||||||
[OSSkipCondition(OperatingSystems.Windows, WindowsVersions.Win7)]
|
[MinimumOSVersion(OperatingSystems.Windows, WindowsVersions.Win81)]
|
||||||
public void DefaultConfigSectionCanSetProtocols_NonMacAndWin7(string input, HttpProtocols expected)
|
public void DefaultConfigSectionCanSetProtocols_NonMacAndWin7(string input, HttpProtocols expected)
|
||||||
=> DefaultConfigSectionCanSetProtocols(input, expected);
|
=> DefaultConfigSectionCanSetProtocols(input, expected);
|
||||||
|
|
||||||
|
|
@ -389,7 +389,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Tests
|
||||||
// [InlineData("http2", HttpProtocols.Http2)] // Not supported due to missing ALPN support. https://github.com/dotnet/corefx/issues/33016
|
// [InlineData("http2", HttpProtocols.Http2)] // Not supported due to missing ALPN support. https://github.com/dotnet/corefx/issues/33016
|
||||||
[InlineData("http1AndHttp2", HttpProtocols.Http1AndHttp2)] // Gracefully falls back to HTTP/1
|
[InlineData("http1AndHttp2", HttpProtocols.Http1AndHttp2)] // Gracefully falls back to HTTP/1
|
||||||
[OSSkipCondition(OperatingSystems.Linux)]
|
[OSSkipCondition(OperatingSystems.Linux)]
|
||||||
[OSSkipCondition(OperatingSystems.Windows, WindowsVersions.Win10, WindowsVersions.Win8, WindowsVersions.Win81)]
|
[OSSkipCondition(OperatingSystems.Windows, WindowsVersions.Win10, WindowsVersions.Win81)]
|
||||||
public void EndpointConfigSectionCanSetProtocols_MacAndWin7(string input, HttpProtocols expected) =>
|
public void EndpointConfigSectionCanSetProtocols_MacAndWin7(string input, HttpProtocols expected) =>
|
||||||
EndpointConfigSectionCanSetProtocols(input, expected);
|
EndpointConfigSectionCanSetProtocols(input, expected);
|
||||||
|
|
||||||
|
|
@ -398,7 +398,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Tests
|
||||||
[InlineData("http2", HttpProtocols.Http2)]
|
[InlineData("http2", HttpProtocols.Http2)]
|
||||||
[InlineData("http1AndHttp2", HttpProtocols.Http1AndHttp2)]
|
[InlineData("http1AndHttp2", HttpProtocols.Http1AndHttp2)]
|
||||||
[OSSkipCondition(OperatingSystems.MacOSX)]
|
[OSSkipCondition(OperatingSystems.MacOSX)]
|
||||||
[OSSkipCondition(OperatingSystems.Windows, WindowsVersions.Win7)]
|
[MinimumOSVersion(OperatingSystems.Windows, WindowsVersions.Win81)]
|
||||||
public void EndpointConfigSectionCanSetProtocols_NonMacAndWin7(string input, HttpProtocols expected) =>
|
public void EndpointConfigSectionCanSetProtocols_NonMacAndWin7(string input, HttpProtocols expected) =>
|
||||||
EndpointConfigSectionCanSetProtocols(input, expected);
|
EndpointConfigSectionCanSetProtocols(input, expected);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests.Http2
|
||||||
|
|
||||||
[ConditionalFact]
|
[ConditionalFact]
|
||||||
[OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX)]
|
[OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX)]
|
||||||
[OSSkipCondition(OperatingSystems.Windows, WindowsVersions.Win10, WindowsVersions.Win8, WindowsVersions.Win81)]
|
[OSSkipCondition(OperatingSystems.Windows, WindowsVersions.Win10, WindowsVersions.Win81)]
|
||||||
// Win7 SslStream is missing ALPN support.
|
// Win7 SslStream is missing ALPN support.
|
||||||
public void TlsAndHttp2NotSupportedOnWin7()
|
public void TlsAndHttp2NotSupportedOnWin7()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests.Http2
|
||||||
|
|
||||||
[CollectDump]
|
[CollectDump]
|
||||||
[ConditionalFact]
|
[ConditionalFact]
|
||||||
[SkipOnHelix("https://github.com/aspnet/AspNetCore/issues/9985", Queues = "Fedora.28.Amd64.Open")] // https://github.com/aspnet/AspNetCore/issues/9985
|
[SkipOnHelix("https://github.com/aspnet/AspNetCore/issues/9985", Queues = "Fedora.28.Amd64.Open")]
|
||||||
[Flaky("https://github.com/aspnet/AspNetCore/issues/9985", FlakyOn.All)]
|
[Flaky("https://github.com/aspnet/AspNetCore/issues/9985", FlakyOn.All)]
|
||||||
public async Task GracefulShutdownWaitsForRequestsToFinish()
|
public async Task GracefulShutdownWaitsForRequestsToFinish()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
|
||||||
#if LIBUV
|
#if LIBUV
|
||||||
[OSSkipCondition(OperatingSystems.Windows, SkipReason = "Libuv does not support unix domain sockets on Windows.")]
|
[OSSkipCondition(OperatingSystems.Windows, SkipReason = "Libuv does not support unix domain sockets on Windows.")]
|
||||||
#else
|
#else
|
||||||
[OSSkipCondition(OperatingSystems.Windows, WindowsVersions.Win7, WindowsVersions.Win8, WindowsVersions.Win81, WindowsVersions.Win2008R2, SkipReason = "UnixDomainSocketEndPoint is not supported on older versions of Windows")]
|
[MinimumOSVersion(OperatingSystems.Windows, WindowsVersions.Win10_RS4)]
|
||||||
#endif
|
#endif
|
||||||
[SkipOnHelix("https://github.com/aspnet/AspNetCore/issues/14382", Queues = "Windows.10.Amd64.Open")]
|
[SkipOnHelix("https://github.com/aspnet/AspNetCore/issues/14382", Queues = "Windows.10.Amd64.Open")]
|
||||||
[ConditionalFact]
|
[ConditionalFact]
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
using Xunit.Sdk;
|
using Xunit.Sdk;
|
||||||
|
|
||||||
namespace OpenQA.Selenium
|
namespace OpenQA.Selenium
|
||||||
|
|
@ -13,15 +14,31 @@ namespace OpenQA.Selenium
|
||||||
// case.
|
// case.
|
||||||
public class BrowserAssertFailedException : XunitException
|
public class BrowserAssertFailedException : XunitException
|
||||||
{
|
{
|
||||||
public BrowserAssertFailedException(IReadOnlyList<LogEntry> logs, Exception innerException, string screenShotPath)
|
public BrowserAssertFailedException(IReadOnlyList<LogEntry> logs, Exception innerException, string screenShotPath, string innerHTML)
|
||||||
: base(BuildMessage(innerException, logs, screenShotPath), innerException)
|
: base(BuildMessage(innerException, logs, screenShotPath, innerHTML), innerException)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string BuildMessage(Exception innerException, IReadOnlyList<LogEntry> logs, string screenShotPath) =>
|
private static string BuildMessage(Exception exception, IReadOnlyList<LogEntry> logs, string screenShotPath, string innerHTML)
|
||||||
innerException.ToString() + Environment.NewLine +
|
{
|
||||||
(File.Exists(screenShotPath) ? $"Screen shot captured at '{screenShotPath}'" + Environment.NewLine : "") +
|
var builder = new StringBuilder();
|
||||||
(logs.Count > 0 ? "Encountered browser logs" : "No browser logs found") + " while running the assertion." + Environment.NewLine +
|
builder.AppendLine(exception.ToString());
|
||||||
string.Join(Environment.NewLine, logs);
|
|
||||||
|
if (File.Exists(screenShotPath))
|
||||||
|
{
|
||||||
|
builder.AppendLine($"Screen shot captured at '{screenShotPath}'");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (logs.Count > 0)
|
||||||
|
{
|
||||||
|
builder.AppendLine("Encountered browser errors")
|
||||||
|
.AppendJoin(Environment.NewLine, logs);
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.AppendLine("Page content:")
|
||||||
|
.AppendLine(innerHTML);
|
||||||
|
|
||||||
|
return builder.ToString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue