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/Middleware/Rewrite @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="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.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="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" />
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
|
|
@ -89,19 +91,26 @@ namespace Microsoft.AspNetCore.Builder
|
|||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
await context.Response.WriteAsync($@"
|
||||
<h1>Unable to find debuggable browser tab</h1>
|
||||
<p>
|
||||
Could not get a list of browser tabs from <code>{debuggerTabsListUrl}</code>.
|
||||
Ensure Chrome is running with debugging enabled.
|
||||
</p>
|
||||
<h2>Resolution</h2>
|
||||
<h1>Unable to find debuggable browser tab</h1>
|
||||
<p>
|
||||
Could not get a list of browser tabs from <code>{debuggerTabsListUrl}</code>.
|
||||
Ensure your browser is running with debugging enabled.
|
||||
</p>
|
||||
<h2>Resolution</h2>
|
||||
<p>
|
||||
<h4>If you are using Google Chrome for your development, follow these instructions:</h4>
|
||||
{GetLaunchChromeInstructions(appRootUrl)}
|
||||
<p>... then use that new tab for debugging.</p>
|
||||
<h2>Underlying exception:</h2>
|
||||
<pre>{ex}</pre>
|
||||
");
|
||||
</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>
|
||||
<pre>{ex}</pre>
|
||||
");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -144,20 +153,42 @@ namespace Microsoft.AspNetCore.Builder
|
|||
|
||||
private static string GetLaunchChromeInstructions(string appRootUrl)
|
||||
{
|
||||
var profilePath = Path.Combine(Path.GetTempPath(), "blazor-edge-debug");
|
||||
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
return $@"<p>Close all Chrome instances, then 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>";
|
||||
return $@"<p>Press Win+R and enter the following:</p>
|
||||
<p><strong><code>chrome --remote-debugging-port=9222 --user-data-dir=""{profilePath}"" {appRootUrl}</code></strong></p>";
|
||||
}
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
{
|
||||
return $@"<p>Close all Chrome instances, then in a terminal window execute the following:</p>
|
||||
<p><strong><code>google-chrome --remote-debugging-port=9222 {appRootUrl}</code></strong></p>";
|
||||
return $@"<p>In a terminal window execute the following:</p>
|
||||
<p><strong><code>google-chrome --remote-debugging-port=9222 --user-data-dir={profilePath} {appRootUrl}</code></strong></p>";
|
||||
}
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
||||
{
|
||||
return $@"<p>Close all Chrome instances, then in a terminal window execute the following:</p>
|
||||
<p><strong><code>open /Applications/Google\ Chrome.app --args --remote-debugging-port=9222 {appRootUrl}</code></strong></p>";
|
||||
return $@"<p>Execute the following:</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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
<span class="text-nowrap">
|
||||
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>
|
||||
and tell us what you think.
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -4,6 +4,16 @@ html, body {
|
|||
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
}
|
||||
|
||||
a, .btn-link {
|
||||
color: #0366d6;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
color: #fff;
|
||||
background-color: #1b6ec2;
|
||||
border-color: #1861ac;
|
||||
}
|
||||
|
||||
app {
|
||||
position: relative;
|
||||
display: flex;
|
||||
|
|
@ -21,10 +31,21 @@ app {
|
|||
}
|
||||
|
||||
.main .top-row {
|
||||
background-color: #e6e6e6;
|
||||
background-color: #f7f7f7;
|
||||
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 {
|
||||
background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%);
|
||||
}
|
||||
|
|
@ -44,38 +65,38 @@ app {
|
|||
top: -2px;
|
||||
}
|
||||
|
||||
.nav-item {
|
||||
font-size: 0.9rem;
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.nav-item:first-of-type {
|
||||
padding-top: 1rem;
|
||||
.sidebar .nav-item {
|
||||
font-size: 0.9rem;
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.nav-item:last-of-type {
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
|
||||
.nav-item a {
|
||||
color: #d7d7d7;
|
||||
border-radius: 4px;
|
||||
height: 3rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
line-height: 3rem;
|
||||
}
|
||||
|
||||
.nav-item a.active {
|
||||
background-color: rgba(255,255,255,0.25);
|
||||
color: white;
|
||||
.sidebar .nav-item:first-of-type {
|
||||
padding-top: 1rem;
|
||||
}
|
||||
|
||||
.nav-item a:hover {
|
||||
background-color: rgba(255,255,255,0.1);
|
||||
color: white;
|
||||
.sidebar .nav-item:last-of-type {
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
|
||||
.sidebar .nav-item a {
|
||||
color: #d7d7d7;
|
||||
border-radius: 4px;
|
||||
height: 3rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
line-height: 3rem;
|
||||
}
|
||||
|
||||
.sidebar .nav-item a.active {
|
||||
background-color: rgba(255,255,255,0.25);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.sidebar .nav-item a:hover {
|
||||
background-color: rgba(255,255,255,0.1);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.content {
|
||||
padding-top: 1.1rem;
|
||||
}
|
||||
|
|
@ -116,9 +137,17 @@ app {
|
|||
}
|
||||
|
||||
@media (max-width: 767.98px) {
|
||||
.main .top-row {
|
||||
.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;
|
||||
}
|
||||
}
|
||||
|
||||
@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 {
|
||||
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
}
|
||||
|
||||
a, .btn-link {
|
||||
color: #0366d6;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
color: #fff;
|
||||
background-color: #1b6ec2;
|
||||
border-color: #1861ac;
|
||||
}
|
||||
|
||||
app {
|
||||
position: relative;
|
||||
display: flex;
|
||||
|
|
@ -21,10 +31,21 @@ app {
|
|||
}
|
||||
|
||||
.main .top-row {
|
||||
background-color: #e6e6e6;
|
||||
background-color: #f7f7f7;
|
||||
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 {
|
||||
background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%);
|
||||
}
|
||||
|
|
@ -44,38 +65,38 @@ app {
|
|||
top: -2px;
|
||||
}
|
||||
|
||||
.nav-item {
|
||||
font-size: 0.9rem;
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.nav-item:first-of-type {
|
||||
padding-top: 1rem;
|
||||
.sidebar .nav-item {
|
||||
font-size: 0.9rem;
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.nav-item:last-of-type {
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
|
||||
.nav-item a {
|
||||
color: #d7d7d7;
|
||||
border-radius: 4px;
|
||||
height: 3rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
line-height: 3rem;
|
||||
}
|
||||
|
||||
.nav-item a.active {
|
||||
background-color: rgba(255,255,255,0.25);
|
||||
color: white;
|
||||
.sidebar .nav-item:first-of-type {
|
||||
padding-top: 1rem;
|
||||
}
|
||||
|
||||
.nav-item a:hover {
|
||||
background-color: rgba(255,255,255,0.1);
|
||||
color: white;
|
||||
.sidebar .nav-item:last-of-type {
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
|
||||
.sidebar .nav-item a {
|
||||
color: #d7d7d7;
|
||||
border-radius: 4px;
|
||||
height: 3rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
line-height: 3rem;
|
||||
}
|
||||
|
||||
.sidebar .nav-item a.active {
|
||||
background-color: rgba(255,255,255,0.25);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.sidebar .nav-item a:hover {
|
||||
background-color: rgba(255,255,255,0.1);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.content {
|
||||
padding-top: 1.1rem;
|
||||
}
|
||||
|
|
@ -96,10 +117,37 @@ app {
|
|||
color: red;
|
||||
}
|
||||
|
||||
#blazor-error-ui {
|
||||
background: lightyellow;
|
||||
bottom: 0;
|
||||
box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
|
||||
display: none;
|
||||
left: 0;
|
||||
padding: 0.6rem 1.25rem 0.7rem 1.25rem;
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
#blazor-error-ui .dismiss {
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
right: 0.75rem;
|
||||
top: 0.5rem;
|
||||
}
|
||||
|
||||
@media (max-width: 767.98px) {
|
||||
.main .top-row {
|
||||
.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;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
|
|
|
|||
|
|
@ -240,6 +240,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ignitor", "Ignitor\src\Igni
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ignitor.Test", "Ignitor\test\Ignitor.Test.csproj", "{F31E8118-014E-4CCE-8A48-5282F7B9BB3E}"
|
||||
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
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
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|x86.ActiveCfg = Release|Any CPU
|
||||
{F31E8118-014E-4CCE-8A48-5282F7B9BB3E}.Release|x86.Build.0 = Release|Any CPU
|
||||
{B70F90C7-2696-4050-B24E-BF0308F4E059}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B70F90C7-2696-4050-B24E-BF0308F4E059}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B70F90C7-2696-4050-B24E-BF0308F4E059}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{B70F90C7-2696-4050-B24E-BF0308F4E059}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{B70F90C7-2696-4050-B24E-BF0308F4E059}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{B70F90C7-2696-4050-B24E-BF0308F4E059}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{B70F90C7-2696-4050-B24E-BF0308F4E059}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B70F90C7-2696-4050-B24E-BF0308F4E059}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{B70F90C7-2696-4050-B24E-BF0308F4E059}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{B70F90C7-2696-4050-B24E-BF0308F4E059}.Release|x64.Build.0 = Release|Any CPU
|
||||
{B70F90C7-2696-4050-B24E-BF0308F4E059}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{B70F90C7-2696-4050-B24E-BF0308F4E059}.Release|x86.Build.0 = Release|Any CPU
|
||||
{A5617A9D-C71E-44DE-936C-27611EB40A02}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A5617A9D-C71E-44DE-936C-27611EB40A02}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A5617A9D-C71E-44DE-936C-27611EB40A02}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{A5617A9D-C71E-44DE-936C-27611EB40A02}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{A5617A9D-C71E-44DE-936C-27611EB40A02}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{A5617A9D-C71E-44DE-936C-27611EB40A02}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{A5617A9D-C71E-44DE-936C-27611EB40A02}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A5617A9D-C71E-44DE-936C-27611EB40A02}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{A5617A9D-C71E-44DE-936C-27611EB40A02}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{A5617A9D-C71E-44DE-936C-27611EB40A02}.Release|x64.Build.0 = Release|Any CPU
|
||||
{A5617A9D-C71E-44DE-936C-27611EB40A02}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{A5617A9D-C71E-44DE-936C-27611EB40A02}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
@ -1596,6 +1626,9 @@ Global
|
|||
{BBF37AF9-8290-4B70-8BA8-0F6017B3B620} = {46E4300C-5726-4108-B9A2-18BB94EB26ED}
|
||||
{CD0EF85C-4187-4515-A355-E5A0D4485F40} = {BDE2397D-C53A-4783-8B3A-1F54F48A6926}
|
||||
{F31E8118-014E-4CCE-8A48-5282F7B9BB3E} = {BDE2397D-C53A-4783-8B3A-1F54F48A6926}
|
||||
{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
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {CC3C47E1-AD1A-4619-9CD3-E08A0148E5CE}
|
||||
|
|
|
|||
|
|
@ -207,7 +207,10 @@ namespace Microsoft.AspNetCore.Components
|
|||
public sealed partial class EventHandlerAttribute : System.Attribute
|
||||
{
|
||||
public EventHandlerAttribute(string attributeName, System.Type eventArgsType) { }
|
||||
public EventHandlerAttribute(string attributeName, System.Type eventArgsType, bool enableStopPropagation, bool enablePreventDefault) { }
|
||||
public string AttributeName { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
|
||||
public bool EnablePreventDefault { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
|
||||
public bool EnableStopPropagation { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
|
||||
public System.Type EventArgsType { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
|
||||
}
|
||||
public partial interface IComponent
|
||||
|
|
|
|||
|
|
@ -207,7 +207,10 @@ namespace Microsoft.AspNetCore.Components
|
|||
public sealed partial class EventHandlerAttribute : System.Attribute
|
||||
{
|
||||
public EventHandlerAttribute(string attributeName, System.Type eventArgsType) { }
|
||||
public EventHandlerAttribute(string attributeName, System.Type eventArgsType, bool enableStopPropagation, bool enablePreventDefault) { }
|
||||
public string AttributeName { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
|
||||
public bool EnablePreventDefault { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
|
||||
public bool EnableStopPropagation { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
|
||||
public System.Type EventArgsType { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
|
||||
}
|
||||
public partial interface IComponent
|
||||
|
|
|
|||
|
|
@ -16,7 +16,18 @@ namespace Microsoft.AspNetCore.Components
|
|||
/// </summary>
|
||||
/// <param name="attributeName"></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)
|
||||
{
|
||||
|
|
@ -30,6 +41,8 @@ namespace Microsoft.AspNetCore.Components
|
|||
|
||||
AttributeName = attributeName;
|
||||
EventArgsType = eventArgsType;
|
||||
EnableStopPropagation = enableStopPropagation;
|
||||
EnablePreventDefault = enablePreventDefault;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -41,5 +54,15 @@ namespace Microsoft.AspNetCore.Components
|
|||
/// Gets the event argument type.
|
||||
/// </summary>
|
||||
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\\Server\\src\\Microsoft.AspNetCore.Blazor.Server.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.Server\\HostedInAspNet.Server.csproj",
|
||||
"Blazor\\testassets\\Microsoft.AspNetCore.Blazor.E2EPerformance\\Microsoft.AspNetCore.Blazor.E2EPerformance.csproj",
|
||||
|
|
|
|||
|
|
@ -52,6 +52,12 @@ namespace Microsoft.AspNetCore.Components.Forms
|
|||
messages.Clear();
|
||||
foreach (var validationResult in validationResults)
|
||||
{
|
||||
if (!validationResult.MemberNames.Any())
|
||||
{
|
||||
messages.Add(new FieldIdentifier(editContext.Model, fieldName: string.Empty), validationResult.ErrorMessage);
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var memberName in validationResult.MemberNames)
|
||||
{
|
||||
messages.Add(editContext.Field(memberName), validationResult.ErrorMessage);
|
||||
|
|
|
|||
|
|
@ -13,17 +13,21 @@ using Microsoft.AspNetCore.SignalR.Protocol;
|
|||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
|
||||
#nullable enable
|
||||
namespace Ignitor
|
||||
{
|
||||
public class BlazorClient : IAsyncDisposable
|
||||
{
|
||||
private const string MarkerPattern = ".*?<!--Blazor:(.*?)-->.*?";
|
||||
private HubConnection? _hubConnection;
|
||||
|
||||
public BlazorClient()
|
||||
{
|
||||
CancellationTokenSource = new CancellationTokenSource();
|
||||
TaskCompletionSource = new TaskCompletionSource<object>();
|
||||
CancellationToken = CancellationTokenSource.Token;
|
||||
TaskCompletionSource = new TaskCompletionSource<object?>();
|
||||
|
||||
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);
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -44,104 +48,103 @@ namespace Ignitor
|
|||
/// Gets the collections of operation results that are captured when <see cref="CaptureOperations"/>
|
||||
/// is true.
|
||||
/// </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 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 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 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)
|
||||
{
|
||||
throw new InvalidOperationException("Invalid state previous task not completed");
|
||||
}
|
||||
|
||||
NextBatchReceived = new CancellableOperation<CapturedRenderBatch>(timeout);
|
||||
|
||||
NextBatchReceived = new CancellableOperation<CapturedRenderBatch?>(timeout, CancellationToken);
|
||||
return NextBatchReceived.Completion.Task;
|
||||
}
|
||||
|
||||
public Task<CapturedJSInteropCall> PrepareForNextJSInterop(TimeSpan? timeout)
|
||||
public Task<CapturedJSInteropCall?> PrepareForNextJSInterop(TimeSpan? timeout)
|
||||
{
|
||||
if (NextJSInteropReceived != null && !NextJSInteropReceived.Disposed)
|
||||
{
|
||||
throw new InvalidOperationException("Invalid state previous task not completed");
|
||||
}
|
||||
|
||||
NextJSInteropReceived = new CancellableOperation<CapturedJSInteropCall>(timeout);
|
||||
NextJSInteropReceived = new CancellableOperation<CapturedJSInteropCall?>(timeout, CancellationToken);
|
||||
|
||||
return NextJSInteropReceived.Completion.Task;
|
||||
}
|
||||
|
||||
public Task<string> PrepareForNextDotNetInterop(TimeSpan? timeout)
|
||||
public Task<string?> PrepareForNextDotNetInterop(TimeSpan? timeout)
|
||||
{
|
||||
if (NextDotNetInteropCompletionReceived != null && !NextDotNetInteropCompletionReceived.Disposed)
|
||||
{
|
||||
throw new InvalidOperationException("Invalid state previous task not completed");
|
||||
}
|
||||
|
||||
NextDotNetInteropCompletionReceived = new CancellableOperation<string>(timeout);
|
||||
NextDotNetInteropCompletionReceived = new CancellableOperation<string?>(timeout, CancellationToken);
|
||||
|
||||
return NextDotNetInteropCompletionReceived.Completion.Task;
|
||||
}
|
||||
|
||||
public Task<string> PrepareForNextCircuitError(TimeSpan? timeout)
|
||||
public Task<string?> PrepareForNextCircuitError(TimeSpan? timeout)
|
||||
{
|
||||
if (NextErrorReceived != null && !NextErrorReceived.Disposed)
|
||||
{
|
||||
throw new InvalidOperationException("Invalid state previous task not completed");
|
||||
}
|
||||
|
||||
NextErrorReceived = new CancellableOperation<string>(timeout);
|
||||
NextErrorReceived = new CancellableOperation<string?>(timeout, CancellationToken);
|
||||
|
||||
return NextErrorReceived.Completion.Task;
|
||||
}
|
||||
|
||||
public Task<Exception> PrepareForNextDisconnect(TimeSpan? timeout)
|
||||
public Task<Exception?> PrepareForNextDisconnect(TimeSpan? timeout)
|
||||
{
|
||||
if (NextDisconnect != null && !NextDisconnect.Disposed)
|
||||
{
|
||||
throw new InvalidOperationException("Invalid state previous task not completed");
|
||||
}
|
||||
|
||||
NextDisconnect = new CancellableOperation<Exception>(timeout);
|
||||
NextDisconnect = new CancellableOperation<Exception?>(timeout, CancellationToken);
|
||||
|
||||
return NextDisconnect.Completion.Task;
|
||||
}
|
||||
|
|
@ -172,44 +175,44 @@ namespace Ignitor
|
|||
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);
|
||||
await action();
|
||||
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);
|
||||
await action();
|
||||
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);
|
||||
await action();
|
||||
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);
|
||||
await action();
|
||||
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);
|
||||
await action();
|
||||
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.
|
||||
var exception = await ExpectDisconnect(async () =>
|
||||
|
|
@ -220,7 +223,7 @@ namespace Ignitor
|
|||
return (error, exception);
|
||||
}
|
||||
|
||||
private async Task<CapturedRenderBatch> WaitForRenderBatch(TimeSpan? timeout = null)
|
||||
private async Task<CapturedRenderBatch?> WaitForRenderBatch(TimeSpan? timeout = null)
|
||||
{
|
||||
if (ImplicitWait)
|
||||
{
|
||||
|
|
@ -233,7 +236,7 @@ namespace Ignitor
|
|||
{
|
||||
return await PrepareForNextBatch(timeout ?? DefaultOperationTimeout);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
catch (TimeoutException) when (FormatError != null)
|
||||
{
|
||||
throw FormatError("Timed out while waiting for batch.");
|
||||
}
|
||||
|
|
@ -242,7 +245,7 @@ namespace Ignitor
|
|||
return null;
|
||||
}
|
||||
|
||||
private async Task<CapturedJSInteropCall> WaitForJSInterop(TimeSpan? timeout = null)
|
||||
private async Task<CapturedJSInteropCall?> WaitForJSInterop(TimeSpan? timeout = null)
|
||||
{
|
||||
if (ImplicitWait)
|
||||
{
|
||||
|
|
@ -255,7 +258,7 @@ namespace Ignitor
|
|||
{
|
||||
return await PrepareForNextJSInterop(timeout ?? DefaultOperationTimeout);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
catch (TimeoutException) when (FormatError != null)
|
||||
{
|
||||
throw FormatError("Timed out while waiting for JS Interop.");
|
||||
}
|
||||
|
|
@ -264,7 +267,7 @@ namespace Ignitor
|
|||
return null;
|
||||
}
|
||||
|
||||
private async Task<string> WaitForDotNetInterop(TimeSpan? timeout = null)
|
||||
private async Task<string?> WaitForDotNetInterop(TimeSpan? timeout = null)
|
||||
{
|
||||
if (ImplicitWait)
|
||||
{
|
||||
|
|
@ -277,7 +280,7 @@ namespace Ignitor
|
|||
{
|
||||
return await PrepareForNextDotNetInterop(timeout ?? DefaultOperationTimeout);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
catch (TimeoutException) when (FormatError != null)
|
||||
{
|
||||
throw FormatError("Timed out while waiting for .NET interop.");
|
||||
}
|
||||
|
|
@ -286,7 +289,7 @@ namespace Ignitor
|
|||
return null;
|
||||
}
|
||||
|
||||
private async Task<string> WaitForCircuitError(TimeSpan? timeout = null)
|
||||
private async Task<string?> WaitForCircuitError(TimeSpan? timeout = null)
|
||||
{
|
||||
if (ImplicitWait)
|
||||
{
|
||||
|
|
@ -299,7 +302,7 @@ namespace Ignitor
|
|||
{
|
||||
return await PrepareForNextCircuitError(timeout ?? DefaultOperationTimeout);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
catch (TimeoutException) when (FormatError != null)
|
||||
{
|
||||
throw FormatError("Timed out while waiting for circuit error.");
|
||||
}
|
||||
|
|
@ -308,7 +311,7 @@ namespace Ignitor
|
|||
return null;
|
||||
}
|
||||
|
||||
private async Task<Exception> WaitForDisconnect(TimeSpan? timeout = null)
|
||||
private async Task<Exception?> WaitForDisconnect(TimeSpan? timeout = null)
|
||||
{
|
||||
if (ImplicitWait)
|
||||
{
|
||||
|
|
@ -321,7 +324,7 @@ namespace Ignitor
|
|||
{
|
||||
return await PrepareForNextDisconnect(timeout ?? DefaultOperationTimeout);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
catch (TimeoutException) when (FormatError != null)
|
||||
{
|
||||
throw FormatError("Timed out while waiting for disconnect.");
|
||||
}
|
||||
|
|
@ -344,7 +347,7 @@ namespace Ignitor
|
|||
}
|
||||
});
|
||||
|
||||
HubConnection = builder.Build();
|
||||
_hubConnection = builder.Build();
|
||||
await HubConnection.StartAsync(CancellationToken);
|
||||
|
||||
HubConnection.On<int, string>("JS.AttachComponent", OnAttachComponent);
|
||||
|
|
@ -354,11 +357,6 @@ namespace Ignitor
|
|||
HubConnection.On<string>("JS.Error", OnError);
|
||||
HubConnection.Closed += OnClosedAsync;
|
||||
|
||||
if (CaptureOperations)
|
||||
{
|
||||
Operations = new Operations();
|
||||
}
|
||||
|
||||
if (!connectAutomatically)
|
||||
{
|
||||
return true;
|
||||
|
|
@ -366,7 +364,7 @@ namespace Ignitor
|
|||
|
||||
var descriptors = await GetPrerenderDescriptors(uri);
|
||||
await ExpectRenderBatch(
|
||||
async () => CircuitId = await HubConnection.InvokeAsync<string>("StartCircuit", uri, uri, descriptors),
|
||||
async () => CircuitId = await HubConnection.InvokeAsync<string>("StartCircuit", uri, uri, descriptors, CancellationToken),
|
||||
DefaultConnectionTimeout);
|
||||
return CircuitId != null;
|
||||
}
|
||||
|
|
@ -415,9 +413,9 @@ namespace Ignitor
|
|||
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)
|
||||
|
|
@ -468,7 +466,14 @@ namespace Ignitor
|
|||
|
||||
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)
|
||||
|
|
@ -485,8 +490,11 @@ namespace Ignitor
|
|||
|
||||
public void Cancel()
|
||||
{
|
||||
CancellationTokenSource.Cancel();
|
||||
CancellationTokenSource.Dispose();
|
||||
if (!CancellationTokenSource.IsCancellationRequested)
|
||||
{
|
||||
CancellationTokenSource.Cancel();
|
||||
CancellationTokenSource.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public ElementNode FindElementById(string id)
|
||||
|
|
@ -519,6 +527,7 @@ namespace Ignitor
|
|||
|
||||
public async ValueTask DisposeAsync()
|
||||
{
|
||||
Cancel();
|
||||
if (HubConnection != null)
|
||||
{
|
||||
await HubConnection.DisposeAsync();
|
||||
|
|
@ -526,3 +535,5 @@ namespace Ignitor
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#nullable restore
|
||||
|
|
|
|||
|
|
@ -5,11 +5,12 @@ using System;
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
#nullable enable
|
||||
namespace Ignitor
|
||||
{
|
||||
internal class CancellableOperation<TResult>
|
||||
{
|
||||
public CancellableOperation(TimeSpan? timeout)
|
||||
public CancellableOperation(TimeSpan? timeout, CancellationToken cancellationToken)
|
||||
{
|
||||
Timeout = timeout;
|
||||
|
||||
|
|
@ -17,25 +18,37 @@ namespace Ignitor
|
|||
Completion.Task.ContinueWith(
|
||||
(task, state) =>
|
||||
{
|
||||
var operation = (CancellableOperation<TResult>)state;
|
||||
var operation = (CancellableOperation<TResult>)state!;
|
||||
operation.Dispose();
|
||||
},
|
||||
this,
|
||||
TaskContinuationOptions.ExecuteSynchronously); // We need to execute synchronously to clean-up before anything else continues
|
||||
|
||||
|
||||
Cancellation = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
|
||||
|
||||
if (Timeout != null && Timeout != System.Threading.Timeout.InfiniteTimeSpan && Timeout != TimeSpan.MaxValue)
|
||||
{
|
||||
Cancellation = new CancellationTokenSource(Timeout.Value);
|
||||
CancellationRegistration = Cancellation.Token.Register(
|
||||
(self) =>
|
||||
{
|
||||
var operation = (CancellableOperation<TResult>)self;
|
||||
operation.Completion.TrySetCanceled(operation.Cancellation.Token);
|
||||
operation.Cancellation.Dispose();
|
||||
operation.CancellationRegistration.Dispose();
|
||||
},
|
||||
this);
|
||||
Cancellation.CancelAfter(Timeout.Value);
|
||||
}
|
||||
|
||||
CancellationRegistration = Cancellation.Token.Register(
|
||||
(self) =>
|
||||
{
|
||||
var operation = (CancellableOperation<TResult>)self!;
|
||||
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
// The operation was externally canceled before it timed out.
|
||||
Dispose();
|
||||
return;
|
||||
}
|
||||
|
||||
operation.Completion.TrySetException(new TimeoutException($"The operation timed out after {Timeout}."));
|
||||
operation.Cancellation?.Dispose();
|
||||
operation.CancellationRegistration.Dispose();
|
||||
},
|
||||
this);
|
||||
}
|
||||
|
||||
public TimeSpan? Timeout { get; }
|
||||
|
|
@ -62,3 +75,4 @@ namespace Ignitor
|
|||
}
|
||||
}
|
||||
}
|
||||
#nullable restore
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
namespace Ignitor
|
||||
{
|
||||
#nullable enable
|
||||
public class ComponentState
|
||||
{
|
||||
public ComponentState(int componentId)
|
||||
|
|
@ -11,6 +12,7 @@ namespace Ignitor
|
|||
}
|
||||
|
||||
public int ComponentId { get; }
|
||||
public IComponent Component { get; }
|
||||
public IComponent? Component { get; }
|
||||
}
|
||||
#nullable restore
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
#nullable enable
|
||||
namespace Ignitor
|
||||
{
|
||||
public abstract class ContainerNode : Node
|
||||
|
|
@ -82,3 +83,4 @@ namespace Ignitor
|
|||
}
|
||||
}
|
||||
}
|
||||
#nullable restore
|
||||
|
|
|
|||
|
|
@ -3,7 +3,9 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
#nullable enable
|
||||
namespace Ignitor
|
||||
{
|
||||
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)
|
||||
{
|
||||
|
|
@ -49,7 +51,7 @@ namespace Ignitor
|
|||
element = null;
|
||||
return false;
|
||||
|
||||
bool TryGetElementFromChildren(Node node, out ElementNode foundNode)
|
||||
bool TryGetElementFromChildren(Node node, out ElementNode? foundNode)
|
||||
{
|
||||
if (node is ElementNode elementNode &&
|
||||
elementNode.Attributes.TryGetValue("id", out var elementId) &&
|
||||
|
|
@ -81,6 +83,7 @@ namespace Ignitor
|
|||
{
|
||||
component = new ComponentNode(componentId);
|
||||
Components.Add(componentId, component);
|
||||
|
||||
}
|
||||
|
||||
ApplyEdits(batch, component, 0, edits);
|
||||
|
|
@ -199,7 +202,7 @@ namespace Ignitor
|
|||
|
||||
case RenderTreeEditType.StepOut:
|
||||
{
|
||||
parent = parent.Parent;
|
||||
parent = parent.Parent ?? throw new InvalidOperationException($"Cannot step out of {parent}");
|
||||
currentDepth--;
|
||||
childIndexAtCurrentDepth = currentDepth == 0 ? childIndex : 0; // The childIndex is only ever nonzero at zero depth
|
||||
break;
|
||||
|
|
@ -469,3 +472,4 @@ namespace Ignitor
|
|||
}
|
||||
}
|
||||
}
|
||||
#nullable restore
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ using System.Text.Json;
|
|||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.SignalR.Client;
|
||||
|
||||
#nullable enable
|
||||
namespace Ignitor
|
||||
{
|
||||
public class ElementNode : ContainerNode
|
||||
|
|
@ -87,7 +88,7 @@ namespace Ignitor
|
|||
return DispatchEventCore(connection, Serialize(webEventDescriptor), Serialize(args));
|
||||
}
|
||||
|
||||
public Task ClickAsync(HubConnection connection)
|
||||
internal Task ClickAsync(HubConnection connection)
|
||||
{
|
||||
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.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
#nullable enable
|
||||
namespace Ignitor
|
||||
{
|
||||
public class Error
|
||||
{
|
||||
public string Stack { get; set; }
|
||||
public string? Stack { get; set; }
|
||||
}
|
||||
}
|
||||
#nullable restore
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
namespace Ignitor
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,10 +1,14 @@
|
|||
// 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.
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace Ignitor
|
||||
{
|
||||
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.IO;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace Ignitor
|
||||
{
|
||||
internal static class NodeSerializer
|
||||
|
|
@ -96,7 +98,7 @@ namespace Ignitor
|
|||
if (attribute.Value != null)
|
||||
{
|
||||
Write("=\"");
|
||||
Write(attribute.Value.ToString());
|
||||
Write(attribute.Value.ToString()!);
|
||||
Write("\"");
|
||||
}
|
||||
}
|
||||
|
|
@ -113,7 +115,7 @@ namespace Ignitor
|
|||
if (properties.Value != null)
|
||||
{
|
||||
Write("=\"");
|
||||
Write(properties.Value.ToString());
|
||||
Write(properties.Value.ToString()!);
|
||||
Write("\"");
|
||||
}
|
||||
}
|
||||
|
|
@ -194,3 +196,4 @@ namespace Ignitor
|
|||
}
|
||||
}
|
||||
}
|
||||
#nullable restore
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
#nullable enable
|
||||
namespace Ignitor
|
||||
{
|
||||
public sealed class Operations
|
||||
|
|
@ -18,3 +19,4 @@ namespace Ignitor
|
|||
public ConcurrentQueue<CapturedJSInteropCall> JSInteropCalls { get; } = new ConcurrentQueue<CapturedJSInteropCall>();
|
||||
}
|
||||
}
|
||||
#nullable restore
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
using System;
|
||||
using System.Text;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace Ignitor
|
||||
{
|
||||
public static class RenderBatchReader
|
||||
|
|
@ -206,7 +208,7 @@ namespace Ignitor
|
|||
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));
|
||||
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.Mvc" />
|
||||
<Reference Include="Microsoft.Extensions.Hosting" />
|
||||
<Reference Include="Microsoft.AspNetCore.Blazor.DataAnnotations.Validation" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -30,66 +30,72 @@ app {
|
|||
flex: 1;
|
||||
}
|
||||
|
||||
.main .top-row {
|
||||
background-color: #f7f7f7;
|
||||
border-bottom: 1px solid #d6d5d5;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
.main .top-row {
|
||||
background-color: #f7f7f7;
|
||||
border-bottom: 1px solid #d6d5d5;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.main .top-row > a {
|
||||
margin-left: 1.5rem;
|
||||
.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 {
|
||||
background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%);
|
||||
}
|
||||
|
||||
.sidebar .top-row {
|
||||
background-color: rgba(0,0,0,0.4);
|
||||
}
|
||||
.sidebar .top-row {
|
||||
background-color: rgba(0,0,0,0.4);
|
||||
}
|
||||
|
||||
.sidebar .navbar-brand {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
.sidebar .navbar-brand {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.sidebar .oi {
|
||||
width: 2rem;
|
||||
font-size: 1.1rem;
|
||||
vertical-align: text-top;
|
||||
top: -2px;
|
||||
}
|
||||
.sidebar .oi {
|
||||
width: 2rem;
|
||||
font-size: 1.1rem;
|
||||
vertical-align: text-top;
|
||||
top: -2px;
|
||||
}
|
||||
|
||||
.nav-item {
|
||||
font-size: 0.9rem;
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
.sidebar .nav-item {
|
||||
font-size: 0.9rem;
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.nav-item:first-of-type {
|
||||
padding-top: 1rem;
|
||||
}
|
||||
.sidebar .nav-item:first-of-type {
|
||||
padding-top: 1rem;
|
||||
}
|
||||
|
||||
.nav-item:last-of-type {
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
.sidebar .nav-item:last-of-type {
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
|
||||
.nav-item a {
|
||||
color: #d7d7d7;
|
||||
border-radius: 4px;
|
||||
height: 3rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
line-height: 3rem;
|
||||
}
|
||||
.sidebar .nav-item a {
|
||||
color: #d7d7d7;
|
||||
border-radius: 4px;
|
||||
height: 3rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
line-height: 3rem;
|
||||
}
|
||||
|
||||
.nav-item a.active {
|
||||
background-color: rgba(255,255,255,0.25);
|
||||
color: white;
|
||||
}
|
||||
.sidebar .nav-item a.active {
|
||||
background-color: rgba(255,255,255,0.25);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.nav-item a:hover {
|
||||
background-color: rgba(255,255,255,0.1);
|
||||
color: white;
|
||||
}
|
||||
.sidebar .nav-item a:hover {
|
||||
background-color: rgba(255,255,255,0.1);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.content {
|
||||
padding-top: 1.1rem;
|
||||
|
|
@ -131,9 +137,17 @@ app {
|
|||
}
|
||||
|
||||
@media (max-width: 767.98px) {
|
||||
.main .top-row {
|
||||
.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;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ using MessagePack;
|
|||
using Microsoft.AspNetCore.Connections;
|
||||
using Microsoft.AspNetCore.Internal;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using Microsoft.AspNetCore.SignalR.Internal;
|
||||
using Microsoft.AspNetCore.SignalR.Protocol;
|
||||
|
||||
namespace Microsoft.AspNetCore.Components.Server.BlazorPack
|
||||
|
|
@ -19,6 +20,7 @@ namespace Microsoft.AspNetCore.Components.Server.BlazorPack
|
|||
/// <summary>
|
||||
/// Implements the SignalR Hub Protocol using MessagePack with limited type support.
|
||||
/// </summary>
|
||||
[NonDefaultHubProtocol]
|
||||
internal sealed class BlazorPackHubProtocol : IHubProtocol
|
||||
{
|
||||
internal const string ProtocolName = "blazorpack";
|
||||
|
|
@ -78,7 +80,7 @@ namespace Microsoft.AspNetCore.Components.Server.BlazorPack
|
|||
message = PingMessage.Instance;
|
||||
return true;
|
||||
case HubProtocolConstants.CloseMessageType:
|
||||
message = CreateCloseMessage(ref reader);
|
||||
message = CreateCloseMessage(ref reader, itemCount);
|
||||
return true;
|
||||
default:
|
||||
// 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));
|
||||
}
|
||||
|
||||
private static CloseMessage CreateCloseMessage(ref MessagePackReader reader)
|
||||
private static CloseMessage CreateCloseMessage(ref MessagePackReader reader, int itemCount)
|
||||
{
|
||||
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)
|
||||
|
|
@ -515,7 +530,7 @@ namespace Microsoft.AspNetCore.Components.Server.BlazorPack
|
|||
|
||||
private void WriteCloseMessage(CloseMessage message, ref MessagePackWriter writer)
|
||||
{
|
||||
writer.WriteArrayHeader(2);
|
||||
writer.WriteArrayHeader(3);
|
||||
writer.Write(HubProtocolConstants.CloseMessageType);
|
||||
if (string.IsNullOrEmpty(message.Error))
|
||||
{
|
||||
|
|
@ -525,6 +540,8 @@ namespace Microsoft.AspNetCore.Components.Server.BlazorPack
|
|||
{
|
||||
writer.Write(message.Error);
|
||||
}
|
||||
|
||||
writer.Write(message.AllowReconnect);
|
||||
}
|
||||
|
||||
private void WritePingMessage(PingMessage _, ref MessagePackWriter writer)
|
||||
|
|
@ -559,6 +576,17 @@ namespace Microsoft.AspNetCore.Components.Server.BlazorPack
|
|||
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)]
|
||||
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
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -225,7 +225,7 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits
|
|||
Log.ConnectionUp(_logger, CircuitId, Client.ConnectionId);
|
||||
|
||||
Renderer.Dispatcher.AssertAccess();
|
||||
|
||||
|
||||
List<Exception> exceptions = null;
|
||||
|
||||
for (var i = 0; i < _circuitHandlers.Length; i++)
|
||||
|
|
@ -254,7 +254,7 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits
|
|||
Log.ConnectionDown(_logger, CircuitId, Client.ConnectionId);
|
||||
|
||||
Renderer.Dispatcher.AssertAccess();
|
||||
|
||||
|
||||
List<Exception> exceptions = null;
|
||||
|
||||
for (var i = 0; i < _circuitHandlers.Length; i++)
|
||||
|
|
@ -545,7 +545,7 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits
|
|||
else
|
||||
{
|
||||
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) {
|
||||
console.error('Cannot start debugging, because the application was not compiled with debugging enabled.');
|
||||
} 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 {
|
||||
launchDebugger();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -125,6 +125,8 @@ namespace Microsoft.AspNetCore.Components.Forms
|
|||
public ValidationSummary() { }
|
||||
[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 { } }
|
||||
[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 virtual void Dispose(bool disposing) { }
|
||||
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 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("onactivate", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onbeforeactivate", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onbeforecopy", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onbeforecut", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onbeforedeactivate", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onbeforepaste", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onblur", typeof(Microsoft.AspNetCore.Components.Web.FocusEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("oncanplay", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("oncanplaythrough", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onchange", typeof(Microsoft.AspNetCore.Components.ChangeEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onclick", typeof(Microsoft.AspNetCore.Components.Web.MouseEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("oncontextmenu", typeof(Microsoft.AspNetCore.Components.Web.MouseEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("oncopy", typeof(Microsoft.AspNetCore.Components.Web.ClipboardEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("oncuechange", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("oncut", typeof(Microsoft.AspNetCore.Components.Web.ClipboardEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondblclick", typeof(Microsoft.AspNetCore.Components.Web.MouseEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondeactivate", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondrag", typeof(Microsoft.AspNetCore.Components.Web.DragEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondragend", typeof(Microsoft.AspNetCore.Components.Web.DragEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondragenter", typeof(Microsoft.AspNetCore.Components.Web.DragEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondragleave", typeof(Microsoft.AspNetCore.Components.Web.DragEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondragover", typeof(Microsoft.AspNetCore.Components.Web.DragEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondragstart", typeof(Microsoft.AspNetCore.Components.Web.DragEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondrop", typeof(Microsoft.AspNetCore.Components.Web.DragEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondurationchange", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onemptied", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onended", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onerror", typeof(Microsoft.AspNetCore.Components.Web.ErrorEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onfocus", typeof(Microsoft.AspNetCore.Components.Web.FocusEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onfocusin", typeof(Microsoft.AspNetCore.Components.Web.FocusEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onfocusout", typeof(Microsoft.AspNetCore.Components.Web.FocusEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onfullscreenchange", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onfullscreenerror", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ongotpointercapture", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("oninput", typeof(Microsoft.AspNetCore.Components.ChangeEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("oninvalid", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onkeydown", typeof(Microsoft.AspNetCore.Components.Web.KeyboardEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onkeypress", typeof(Microsoft.AspNetCore.Components.Web.KeyboardEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onkeyup", typeof(Microsoft.AspNetCore.Components.Web.KeyboardEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onload", typeof(Microsoft.AspNetCore.Components.Web.ProgressEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onloadeddata", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onloadedmetadata", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onloadend", typeof(Microsoft.AspNetCore.Components.Web.ProgressEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onloadstart", typeof(Microsoft.AspNetCore.Components.Web.ProgressEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onlostpointercapture", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onmousedown", typeof(Microsoft.AspNetCore.Components.Web.MouseEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onmousemove", typeof(Microsoft.AspNetCore.Components.Web.MouseEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onmouseout", typeof(Microsoft.AspNetCore.Components.Web.MouseEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onmouseover", typeof(Microsoft.AspNetCore.Components.Web.MouseEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onmouseup", typeof(Microsoft.AspNetCore.Components.Web.MouseEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onmousewheel", typeof(Microsoft.AspNetCore.Components.Web.WheelEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpaste", typeof(Microsoft.AspNetCore.Components.Web.ClipboardEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpause", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onplay", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onplaying", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointercancel", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointerdown", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointerenter", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointerleave", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointerlockchange", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointerlockerror", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointermove", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointerout", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointerover", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointerup", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onprogress", typeof(Microsoft.AspNetCore.Components.Web.ProgressEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onratechange", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onreadystatechange", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onreset", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onscroll", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onseeked", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onseeking", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onselect", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onselectionchange", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onselectstart", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onstalled", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onstop", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onsubmit", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onsuspend", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ontimeout", typeof(Microsoft.AspNetCore.Components.Web.ProgressEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ontimeupdate", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ontouchcancel", typeof(Microsoft.AspNetCore.Components.Web.TouchEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ontouchend", typeof(Microsoft.AspNetCore.Components.Web.TouchEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ontouchenter", typeof(Microsoft.AspNetCore.Components.Web.TouchEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ontouchleave", typeof(Microsoft.AspNetCore.Components.Web.TouchEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ontouchmove", typeof(Microsoft.AspNetCore.Components.Web.TouchEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ontouchstart", typeof(Microsoft.AspNetCore.Components.Web.TouchEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onvolumechange", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onwaiting", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onwheel", typeof(Microsoft.AspNetCore.Components.Web.WheelEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onabort", typeof(Microsoft.AspNetCore.Components.Web.ProgressEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onactivate", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onbeforeactivate", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onbeforecopy", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onbeforecut", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onbeforedeactivate", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onbeforepaste", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onblur", typeof(Microsoft.AspNetCore.Components.Web.FocusEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("oncanplay", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("oncanplaythrough", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onchange", typeof(Microsoft.AspNetCore.Components.ChangeEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onclick", typeof(Microsoft.AspNetCore.Components.Web.MouseEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("oncontextmenu", typeof(Microsoft.AspNetCore.Components.Web.MouseEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("oncopy", typeof(Microsoft.AspNetCore.Components.Web.ClipboardEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("oncuechange", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("oncut", typeof(Microsoft.AspNetCore.Components.Web.ClipboardEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondblclick", typeof(Microsoft.AspNetCore.Components.Web.MouseEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondeactivate", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondrag", typeof(Microsoft.AspNetCore.Components.Web.DragEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondragend", typeof(Microsoft.AspNetCore.Components.Web.DragEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondragenter", typeof(Microsoft.AspNetCore.Components.Web.DragEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondragleave", typeof(Microsoft.AspNetCore.Components.Web.DragEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondragover", typeof(Microsoft.AspNetCore.Components.Web.DragEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondragstart", typeof(Microsoft.AspNetCore.Components.Web.DragEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondrop", typeof(Microsoft.AspNetCore.Components.Web.DragEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondurationchange", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onemptied", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onended", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onerror", typeof(Microsoft.AspNetCore.Components.Web.ErrorEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onfocus", typeof(Microsoft.AspNetCore.Components.Web.FocusEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onfocusin", typeof(Microsoft.AspNetCore.Components.Web.FocusEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onfocusout", typeof(Microsoft.AspNetCore.Components.Web.FocusEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onfullscreenchange", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onfullscreenerror", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ongotpointercapture", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("oninput", typeof(Microsoft.AspNetCore.Components.ChangeEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("oninvalid", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onkeydown", typeof(Microsoft.AspNetCore.Components.Web.KeyboardEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onkeypress", typeof(Microsoft.AspNetCore.Components.Web.KeyboardEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onkeyup", typeof(Microsoft.AspNetCore.Components.Web.KeyboardEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onload", typeof(Microsoft.AspNetCore.Components.Web.ProgressEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onloadeddata", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onloadedmetadata", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onloadend", typeof(Microsoft.AspNetCore.Components.Web.ProgressEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onloadstart", typeof(Microsoft.AspNetCore.Components.Web.ProgressEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onlostpointercapture", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onmousedown", typeof(Microsoft.AspNetCore.Components.Web.MouseEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onmousemove", typeof(Microsoft.AspNetCore.Components.Web.MouseEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onmouseout", typeof(Microsoft.AspNetCore.Components.Web.MouseEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onmouseover", typeof(Microsoft.AspNetCore.Components.Web.MouseEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onmouseup", typeof(Microsoft.AspNetCore.Components.Web.MouseEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onmousewheel", typeof(Microsoft.AspNetCore.Components.Web.WheelEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpaste", typeof(Microsoft.AspNetCore.Components.Web.ClipboardEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpause", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onplay", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onplaying", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointercancel", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointerdown", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointerenter", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointerleave", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointerlockchange", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointerlockerror", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointermove", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointerout", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointerover", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointerup", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onprogress", typeof(Microsoft.AspNetCore.Components.Web.ProgressEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onratechange", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onreadystatechange", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onreset", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onscroll", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onseeked", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onseeking", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onselect", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onselectionchange", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onselectstart", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onstalled", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onstop", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onsubmit", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onsuspend", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ontimeout", typeof(Microsoft.AspNetCore.Components.Web.ProgressEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ontimeupdate", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ontouchcancel", typeof(Microsoft.AspNetCore.Components.Web.TouchEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ontouchend", typeof(Microsoft.AspNetCore.Components.Web.TouchEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ontouchenter", typeof(Microsoft.AspNetCore.Components.Web.TouchEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ontouchleave", typeof(Microsoft.AspNetCore.Components.Web.TouchEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ontouchmove", typeof(Microsoft.AspNetCore.Components.Web.TouchEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ontouchstart", typeof(Microsoft.AspNetCore.Components.Web.TouchEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onvolumechange", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onwaiting", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onwheel", typeof(Microsoft.AspNetCore.Components.Web.WheelEventArgs), true, true)]
|
||||
public static partial class EventHandlers
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -125,6 +125,8 @@ namespace Microsoft.AspNetCore.Components.Forms
|
|||
public ValidationSummary() { }
|
||||
[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 { } }
|
||||
[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 virtual void Dispose(bool disposing) { }
|
||||
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 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("onactivate", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onbeforeactivate", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onbeforecopy", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onbeforecut", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onbeforedeactivate", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onbeforepaste", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onblur", typeof(Microsoft.AspNetCore.Components.Web.FocusEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("oncanplay", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("oncanplaythrough", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onchange", typeof(Microsoft.AspNetCore.Components.ChangeEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onclick", typeof(Microsoft.AspNetCore.Components.Web.MouseEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("oncontextmenu", typeof(Microsoft.AspNetCore.Components.Web.MouseEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("oncopy", typeof(Microsoft.AspNetCore.Components.Web.ClipboardEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("oncuechange", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("oncut", typeof(Microsoft.AspNetCore.Components.Web.ClipboardEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondblclick", typeof(Microsoft.AspNetCore.Components.Web.MouseEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondeactivate", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondrag", typeof(Microsoft.AspNetCore.Components.Web.DragEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondragend", typeof(Microsoft.AspNetCore.Components.Web.DragEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondragenter", typeof(Microsoft.AspNetCore.Components.Web.DragEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondragleave", typeof(Microsoft.AspNetCore.Components.Web.DragEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondragover", typeof(Microsoft.AspNetCore.Components.Web.DragEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondragstart", typeof(Microsoft.AspNetCore.Components.Web.DragEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondrop", typeof(Microsoft.AspNetCore.Components.Web.DragEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondurationchange", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onemptied", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onended", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onerror", typeof(Microsoft.AspNetCore.Components.Web.ErrorEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onfocus", typeof(Microsoft.AspNetCore.Components.Web.FocusEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onfocusin", typeof(Microsoft.AspNetCore.Components.Web.FocusEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onfocusout", typeof(Microsoft.AspNetCore.Components.Web.FocusEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onfullscreenchange", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onfullscreenerror", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ongotpointercapture", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("oninput", typeof(Microsoft.AspNetCore.Components.ChangeEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("oninvalid", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onkeydown", typeof(Microsoft.AspNetCore.Components.Web.KeyboardEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onkeypress", typeof(Microsoft.AspNetCore.Components.Web.KeyboardEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onkeyup", typeof(Microsoft.AspNetCore.Components.Web.KeyboardEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onload", typeof(Microsoft.AspNetCore.Components.Web.ProgressEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onloadeddata", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onloadedmetadata", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onloadend", typeof(Microsoft.AspNetCore.Components.Web.ProgressEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onloadstart", typeof(Microsoft.AspNetCore.Components.Web.ProgressEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onlostpointercapture", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onmousedown", typeof(Microsoft.AspNetCore.Components.Web.MouseEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onmousemove", typeof(Microsoft.AspNetCore.Components.Web.MouseEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onmouseout", typeof(Microsoft.AspNetCore.Components.Web.MouseEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onmouseover", typeof(Microsoft.AspNetCore.Components.Web.MouseEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onmouseup", typeof(Microsoft.AspNetCore.Components.Web.MouseEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onmousewheel", typeof(Microsoft.AspNetCore.Components.Web.WheelEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpaste", typeof(Microsoft.AspNetCore.Components.Web.ClipboardEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpause", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onplay", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onplaying", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointercancel", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointerdown", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointerenter", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointerleave", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointerlockchange", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointerlockerror", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointermove", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointerout", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointerover", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointerup", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onprogress", typeof(Microsoft.AspNetCore.Components.Web.ProgressEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onratechange", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onreadystatechange", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onreset", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onscroll", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onseeked", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onseeking", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onselect", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onselectionchange", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onselectstart", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onstalled", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onstop", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onsubmit", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onsuspend", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ontimeout", typeof(Microsoft.AspNetCore.Components.Web.ProgressEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ontimeupdate", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ontouchcancel", typeof(Microsoft.AspNetCore.Components.Web.TouchEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ontouchend", typeof(Microsoft.AspNetCore.Components.Web.TouchEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ontouchenter", typeof(Microsoft.AspNetCore.Components.Web.TouchEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ontouchleave", typeof(Microsoft.AspNetCore.Components.Web.TouchEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ontouchmove", typeof(Microsoft.AspNetCore.Components.Web.TouchEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ontouchstart", typeof(Microsoft.AspNetCore.Components.Web.TouchEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onvolumechange", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onwaiting", typeof(System.EventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onwheel", typeof(Microsoft.AspNetCore.Components.Web.WheelEventArgs))]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onabort", typeof(Microsoft.AspNetCore.Components.Web.ProgressEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onactivate", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onbeforeactivate", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onbeforecopy", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onbeforecut", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onbeforedeactivate", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onbeforepaste", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onblur", typeof(Microsoft.AspNetCore.Components.Web.FocusEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("oncanplay", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("oncanplaythrough", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onchange", typeof(Microsoft.AspNetCore.Components.ChangeEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onclick", typeof(Microsoft.AspNetCore.Components.Web.MouseEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("oncontextmenu", typeof(Microsoft.AspNetCore.Components.Web.MouseEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("oncopy", typeof(Microsoft.AspNetCore.Components.Web.ClipboardEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("oncuechange", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("oncut", typeof(Microsoft.AspNetCore.Components.Web.ClipboardEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondblclick", typeof(Microsoft.AspNetCore.Components.Web.MouseEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondeactivate", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondrag", typeof(Microsoft.AspNetCore.Components.Web.DragEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondragend", typeof(Microsoft.AspNetCore.Components.Web.DragEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondragenter", typeof(Microsoft.AspNetCore.Components.Web.DragEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondragleave", typeof(Microsoft.AspNetCore.Components.Web.DragEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondragover", typeof(Microsoft.AspNetCore.Components.Web.DragEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondragstart", typeof(Microsoft.AspNetCore.Components.Web.DragEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondrop", typeof(Microsoft.AspNetCore.Components.Web.DragEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ondurationchange", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onemptied", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onended", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onerror", typeof(Microsoft.AspNetCore.Components.Web.ErrorEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onfocus", typeof(Microsoft.AspNetCore.Components.Web.FocusEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onfocusin", typeof(Microsoft.AspNetCore.Components.Web.FocusEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onfocusout", typeof(Microsoft.AspNetCore.Components.Web.FocusEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onfullscreenchange", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onfullscreenerror", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ongotpointercapture", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("oninput", typeof(Microsoft.AspNetCore.Components.ChangeEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("oninvalid", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onkeydown", typeof(Microsoft.AspNetCore.Components.Web.KeyboardEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onkeypress", typeof(Microsoft.AspNetCore.Components.Web.KeyboardEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onkeyup", typeof(Microsoft.AspNetCore.Components.Web.KeyboardEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onload", typeof(Microsoft.AspNetCore.Components.Web.ProgressEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onloadeddata", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onloadedmetadata", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onloadend", typeof(Microsoft.AspNetCore.Components.Web.ProgressEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onloadstart", typeof(Microsoft.AspNetCore.Components.Web.ProgressEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onlostpointercapture", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onmousedown", typeof(Microsoft.AspNetCore.Components.Web.MouseEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onmousemove", typeof(Microsoft.AspNetCore.Components.Web.MouseEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onmouseout", typeof(Microsoft.AspNetCore.Components.Web.MouseEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onmouseover", typeof(Microsoft.AspNetCore.Components.Web.MouseEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onmouseup", typeof(Microsoft.AspNetCore.Components.Web.MouseEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onmousewheel", typeof(Microsoft.AspNetCore.Components.Web.WheelEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpaste", typeof(Microsoft.AspNetCore.Components.Web.ClipboardEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpause", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onplay", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onplaying", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointercancel", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointerdown", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointerenter", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointerleave", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointerlockchange", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointerlockerror", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointermove", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointerout", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointerover", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onpointerup", typeof(Microsoft.AspNetCore.Components.Web.PointerEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onprogress", typeof(Microsoft.AspNetCore.Components.Web.ProgressEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onratechange", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onreadystatechange", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onreset", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onscroll", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onseeked", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onseeking", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onselect", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onselectionchange", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onselectstart", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onstalled", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onstop", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onsubmit", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onsuspend", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ontimeout", typeof(Microsoft.AspNetCore.Components.Web.ProgressEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ontimeupdate", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ontouchcancel", typeof(Microsoft.AspNetCore.Components.Web.TouchEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ontouchend", typeof(Microsoft.AspNetCore.Components.Web.TouchEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ontouchenter", typeof(Microsoft.AspNetCore.Components.Web.TouchEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ontouchleave", typeof(Microsoft.AspNetCore.Components.Web.TouchEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ontouchmove", typeof(Microsoft.AspNetCore.Components.Web.TouchEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("ontouchstart", typeof(Microsoft.AspNetCore.Components.Web.TouchEventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onvolumechange", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onwaiting", typeof(System.EventArgs), true, true)]
|
||||
[Microsoft.AspNetCore.Components.EventHandlerAttribute("onwheel", typeof(Microsoft.AspNetCore.Components.Web.WheelEventArgs), true, true)]
|
||||
public static partial class EventHandlers
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,12 @@ namespace Microsoft.AspNetCore.Components.Forms
|
|||
private EditContext _previousEditContext;
|
||||
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>
|
||||
/// Gets or sets a collection of additional attributes that will be applied to the created <c>ul</c> element.
|
||||
/// </summary>
|
||||
|
|
@ -57,22 +63,31 @@ namespace Microsoft.AspNetCore.Components.Forms
|
|||
{
|
||||
// As an optimization, only evaluate the messages enumerable once, and
|
||||
// only produce the enclosing <ul> if there's at least one message
|
||||
var messagesEnumerator = CurrentEditContext.GetValidationMessages().GetEnumerator();
|
||||
if (messagesEnumerator.MoveNext())
|
||||
var validationMessages = Model is null ?
|
||||
CurrentEditContext.GetValidationMessages() :
|
||||
CurrentEditContext.GetValidationMessages(new FieldIdentifier(Model, string.Empty));
|
||||
|
||||
var first = true;
|
||||
foreach (var error in validationMessages)
|
||||
{
|
||||
builder.OpenElement(0, "ul");
|
||||
builder.AddMultipleAttributes(1, AdditionalAttributes);
|
||||
builder.AddAttribute(2, "class", "validation-errors");
|
||||
|
||||
do
|
||||
if (first)
|
||||
{
|
||||
builder.OpenElement(3, "li");
|
||||
builder.AddAttribute(4, "class", "validation-message");
|
||||
builder.AddContent(5, messagesEnumerator.Current);
|
||||
builder.CloseElement();
|
||||
}
|
||||
while (messagesEnumerator.MoveNext());
|
||||
first = false;
|
||||
|
||||
builder.OpenElement(0, "ul");
|
||||
builder.AddMultipleAttributes(1, AdditionalAttributes);
|
||||
builder.AddAttribute(2, "class", "validation-errors");
|
||||
}
|
||||
|
||||
builder.OpenElement(3, "li");
|
||||
builder.AddAttribute(4, "class", "validation-message");
|
||||
builder.AddContent(5, error);
|
||||
builder.CloseElement();
|
||||
}
|
||||
|
||||
if (!first)
|
||||
{
|
||||
// We have at least one validation message.
|
||||
builder.CloseElement();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,117 +11,117 @@ namespace Microsoft.AspNetCore.Components.Web
|
|||
/// </summary>
|
||||
|
||||
// Focus events
|
||||
[EventHandler("onfocus", typeof(FocusEventArgs))]
|
||||
[EventHandler("onblur", typeof(FocusEventArgs))]
|
||||
[EventHandler("onfocusin", typeof(FocusEventArgs))]
|
||||
[EventHandler("onfocusout", typeof(FocusEventArgs))]
|
||||
[EventHandler("onfocus", typeof(FocusEventArgs), true, true)]
|
||||
[EventHandler("onblur", typeof(FocusEventArgs), true, true)]
|
||||
[EventHandler("onfocusin", typeof(FocusEventArgs), true, true)]
|
||||
[EventHandler("onfocusout", typeof(FocusEventArgs), true, true)]
|
||||
|
||||
// Mouse events
|
||||
[EventHandler("onmouseover", typeof(MouseEventArgs))]
|
||||
[EventHandler("onmouseout", typeof(MouseEventArgs))]
|
||||
[EventHandler("onmousemove", typeof(MouseEventArgs))]
|
||||
[EventHandler("onmousedown", typeof(MouseEventArgs))]
|
||||
[EventHandler("onmouseup", typeof(MouseEventArgs))]
|
||||
[EventHandler("onclick", typeof(MouseEventArgs))]
|
||||
[EventHandler("ondblclick", typeof(MouseEventArgs))]
|
||||
[EventHandler("onwheel", typeof(WheelEventArgs))]
|
||||
[EventHandler("onmousewheel", typeof(WheelEventArgs))]
|
||||
[EventHandler("oncontextmenu", typeof(MouseEventArgs))]
|
||||
[EventHandler("onmouseover", typeof(MouseEventArgs), true, true)]
|
||||
[EventHandler("onmouseout", typeof(MouseEventArgs), true, true)]
|
||||
[EventHandler("onmousemove", typeof(MouseEventArgs), true, true)]
|
||||
[EventHandler("onmousedown", typeof(MouseEventArgs), true, true)]
|
||||
[EventHandler("onmouseup", typeof(MouseEventArgs), true, true)]
|
||||
[EventHandler("onclick", typeof(MouseEventArgs), true, true)]
|
||||
[EventHandler("ondblclick", typeof(MouseEventArgs), true, true)]
|
||||
[EventHandler("onwheel", typeof(WheelEventArgs), true, true)]
|
||||
[EventHandler("onmousewheel", typeof(WheelEventArgs), true, true)]
|
||||
[EventHandler("oncontextmenu", typeof(MouseEventArgs), true, true)]
|
||||
|
||||
// Drag events
|
||||
[EventHandler("ondrag", typeof(DragEventArgs))]
|
||||
[EventHandler("ondragend", typeof(DragEventArgs))]
|
||||
[EventHandler("ondragenter", typeof(DragEventArgs))]
|
||||
[EventHandler("ondragleave", typeof(DragEventArgs))]
|
||||
[EventHandler("ondragover", typeof(DragEventArgs))]
|
||||
[EventHandler("ondragstart", typeof(DragEventArgs))]
|
||||
[EventHandler("ondrop", typeof(DragEventArgs))]
|
||||
[EventHandler("ondrag", typeof(DragEventArgs), true, true)]
|
||||
[EventHandler("ondragend", typeof(DragEventArgs), true, true)]
|
||||
[EventHandler("ondragenter", typeof(DragEventArgs), true, true)]
|
||||
[EventHandler("ondragleave", typeof(DragEventArgs), true, true)]
|
||||
[EventHandler("ondragover", typeof(DragEventArgs), true, true)]
|
||||
[EventHandler("ondragstart", typeof(DragEventArgs), true, true)]
|
||||
[EventHandler("ondrop", typeof(DragEventArgs), true, true)]
|
||||
|
||||
// Keyboard events
|
||||
[EventHandler("onkeydown", typeof(KeyboardEventArgs))]
|
||||
[EventHandler("onkeyup", typeof(KeyboardEventArgs))]
|
||||
[EventHandler("onkeypress", typeof(KeyboardEventArgs))]
|
||||
[EventHandler("onkeydown", typeof(KeyboardEventArgs), true, true)]
|
||||
[EventHandler("onkeyup", typeof(KeyboardEventArgs), true, true)]
|
||||
[EventHandler("onkeypress", typeof(KeyboardEventArgs), true, true)]
|
||||
|
||||
// Input events
|
||||
[EventHandler("onchange", typeof(ChangeEventArgs))]
|
||||
[EventHandler("oninput", typeof(ChangeEventArgs))]
|
||||
[EventHandler("oninvalid", typeof(EventArgs))]
|
||||
[EventHandler("onreset", typeof(EventArgs))]
|
||||
[EventHandler("onselect", typeof(EventArgs))]
|
||||
[EventHandler("onselectstart", typeof(EventArgs))]
|
||||
[EventHandler("onselectionchange", typeof(EventArgs))]
|
||||
[EventHandler("onsubmit", typeof(EventArgs))]
|
||||
[EventHandler("onchange", typeof(ChangeEventArgs), true, true)]
|
||||
[EventHandler("oninput", typeof(ChangeEventArgs), true, true)]
|
||||
[EventHandler("oninvalid", typeof(EventArgs), true, true)]
|
||||
[EventHandler("onreset", typeof(EventArgs), true, true)]
|
||||
[EventHandler("onselect", typeof(EventArgs), true, true)]
|
||||
[EventHandler("onselectstart", typeof(EventArgs), true, true)]
|
||||
[EventHandler("onselectionchange", typeof(EventArgs), true, true)]
|
||||
[EventHandler("onsubmit", typeof(EventArgs), true, true)]
|
||||
|
||||
// Clipboard events
|
||||
[EventHandler("onbeforecopy", typeof(EventArgs))]
|
||||
[EventHandler("onbeforecut", typeof(EventArgs))]
|
||||
[EventHandler("onbeforepaste", typeof(EventArgs))]
|
||||
[EventHandler("oncopy", typeof(ClipboardEventArgs))]
|
||||
[EventHandler("oncut", typeof(ClipboardEventArgs))]
|
||||
[EventHandler("onpaste", typeof(ClipboardEventArgs))]
|
||||
[EventHandler("onbeforecopy", typeof(EventArgs), true, true)]
|
||||
[EventHandler("onbeforecut", typeof(EventArgs), true, true)]
|
||||
[EventHandler("onbeforepaste", typeof(EventArgs), true, true)]
|
||||
[EventHandler("oncopy", typeof(ClipboardEventArgs), true, true)]
|
||||
[EventHandler("oncut", typeof(ClipboardEventArgs), true, true)]
|
||||
[EventHandler("onpaste", typeof(ClipboardEventArgs), true, true)]
|
||||
|
||||
// Touch events
|
||||
[EventHandler("ontouchcancel", typeof(TouchEventArgs))]
|
||||
[EventHandler("ontouchend", typeof(TouchEventArgs))]
|
||||
[EventHandler("ontouchmove", typeof(TouchEventArgs))]
|
||||
[EventHandler("ontouchstart", typeof(TouchEventArgs))]
|
||||
[EventHandler("ontouchenter", typeof(TouchEventArgs))]
|
||||
[EventHandler("ontouchleave", typeof(TouchEventArgs))]
|
||||
[EventHandler("ontouchcancel", typeof(TouchEventArgs), true, true)]
|
||||
[EventHandler("ontouchend", typeof(TouchEventArgs), true, true)]
|
||||
[EventHandler("ontouchmove", typeof(TouchEventArgs), true, true)]
|
||||
[EventHandler("ontouchstart", typeof(TouchEventArgs), true, true)]
|
||||
[EventHandler("ontouchenter", typeof(TouchEventArgs), true, true)]
|
||||
[EventHandler("ontouchleave", typeof(TouchEventArgs), true, true)]
|
||||
|
||||
// Pointer events
|
||||
[EventHandler("ongotpointercapture", typeof(PointerEventArgs))]
|
||||
[EventHandler("onlostpointercapture", typeof(PointerEventArgs))]
|
||||
[EventHandler("onpointercancel", typeof(PointerEventArgs))]
|
||||
[EventHandler("onpointerdown", typeof(PointerEventArgs))]
|
||||
[EventHandler("onpointerenter", typeof(PointerEventArgs))]
|
||||
[EventHandler("onpointerleave", typeof(PointerEventArgs))]
|
||||
[EventHandler("onpointermove", typeof(PointerEventArgs))]
|
||||
[EventHandler("onpointerout", typeof(PointerEventArgs))]
|
||||
[EventHandler("onpointerover", typeof(PointerEventArgs))]
|
||||
[EventHandler("onpointerup", typeof(PointerEventArgs))]
|
||||
[EventHandler("ongotpointercapture", typeof(PointerEventArgs), true, true)]
|
||||
[EventHandler("onlostpointercapture", typeof(PointerEventArgs), true, true)]
|
||||
[EventHandler("onpointercancel", typeof(PointerEventArgs), true, true)]
|
||||
[EventHandler("onpointerdown", typeof(PointerEventArgs), true, true)]
|
||||
[EventHandler("onpointerenter", typeof(PointerEventArgs), true, true)]
|
||||
[EventHandler("onpointerleave", typeof(PointerEventArgs), true, true)]
|
||||
[EventHandler("onpointermove", typeof(PointerEventArgs), true, true)]
|
||||
[EventHandler("onpointerout", typeof(PointerEventArgs), true, true)]
|
||||
[EventHandler("onpointerover", typeof(PointerEventArgs), true, true)]
|
||||
[EventHandler("onpointerup", typeof(PointerEventArgs), true, true)]
|
||||
|
||||
// Media events
|
||||
[EventHandler("oncanplay", typeof(EventArgs))]
|
||||
[EventHandler("oncanplaythrough", typeof(EventArgs))]
|
||||
[EventHandler("oncuechange", typeof(EventArgs))]
|
||||
[EventHandler("ondurationchange", typeof(EventArgs))]
|
||||
[EventHandler("onemptied", typeof(EventArgs))]
|
||||
[EventHandler("onpause", typeof(EventArgs))]
|
||||
[EventHandler("onplay", typeof(EventArgs))]
|
||||
[EventHandler("onplaying", typeof(EventArgs))]
|
||||
[EventHandler("onratechange", typeof(EventArgs))]
|
||||
[EventHandler("onseeked", typeof(EventArgs))]
|
||||
[EventHandler("onseeking", typeof(EventArgs))]
|
||||
[EventHandler("onstalled", typeof(EventArgs))]
|
||||
[EventHandler("onstop", typeof(EventArgs))]
|
||||
[EventHandler("onsuspend", typeof(EventArgs))]
|
||||
[EventHandler("ontimeupdate", typeof(EventArgs))]
|
||||
[EventHandler("onvolumechange", typeof(EventArgs))]
|
||||
[EventHandler("onwaiting", typeof(EventArgs))]
|
||||
[EventHandler("oncanplay", typeof(EventArgs), true, true)]
|
||||
[EventHandler("oncanplaythrough", typeof(EventArgs), true, true)]
|
||||
[EventHandler("oncuechange", typeof(EventArgs), true, true)]
|
||||
[EventHandler("ondurationchange", typeof(EventArgs), true, true)]
|
||||
[EventHandler("onemptied", typeof(EventArgs), true, true)]
|
||||
[EventHandler("onpause", typeof(EventArgs), true, true)]
|
||||
[EventHandler("onplay", typeof(EventArgs), true, true)]
|
||||
[EventHandler("onplaying", typeof(EventArgs), true, true)]
|
||||
[EventHandler("onratechange", typeof(EventArgs), true, true)]
|
||||
[EventHandler("onseeked", typeof(EventArgs), true, true)]
|
||||
[EventHandler("onseeking", typeof(EventArgs), true, true)]
|
||||
[EventHandler("onstalled", typeof(EventArgs), true, true)]
|
||||
[EventHandler("onstop", typeof(EventArgs), true, true)]
|
||||
[EventHandler("onsuspend", typeof(EventArgs), true, true)]
|
||||
[EventHandler("ontimeupdate", typeof(EventArgs), true, true)]
|
||||
[EventHandler("onvolumechange", typeof(EventArgs), true, true)]
|
||||
[EventHandler("onwaiting", typeof(EventArgs), true, true)]
|
||||
|
||||
// Progress events
|
||||
[EventHandler("onloadstart", typeof(ProgressEventArgs))]
|
||||
[EventHandler("ontimeout", typeof(ProgressEventArgs))]
|
||||
[EventHandler("onabort", typeof(ProgressEventArgs))]
|
||||
[EventHandler("onload", typeof(ProgressEventArgs))]
|
||||
[EventHandler("onloadend", typeof(ProgressEventArgs))]
|
||||
[EventHandler("onprogress", typeof(ProgressEventArgs))]
|
||||
[EventHandler("onerror", typeof(ErrorEventArgs))]
|
||||
[EventHandler("onloadstart", typeof(ProgressEventArgs), true, true)]
|
||||
[EventHandler("ontimeout", typeof(ProgressEventArgs), true, true)]
|
||||
[EventHandler("onabort", typeof(ProgressEventArgs), true, true)]
|
||||
[EventHandler("onload", typeof(ProgressEventArgs), true, true)]
|
||||
[EventHandler("onloadend", typeof(ProgressEventArgs), true, true)]
|
||||
[EventHandler("onprogress", typeof(ProgressEventArgs), true, true)]
|
||||
[EventHandler("onerror", typeof(ErrorEventArgs), true, true)]
|
||||
|
||||
// General events
|
||||
[EventHandler("onactivate", typeof(EventArgs))]
|
||||
[EventHandler("onbeforeactivate", typeof(EventArgs))]
|
||||
[EventHandler("onbeforedeactivate", typeof(EventArgs))]
|
||||
[EventHandler("ondeactivate", typeof(EventArgs))]
|
||||
[EventHandler("onended", typeof(EventArgs))]
|
||||
[EventHandler("onfullscreenchange", typeof(EventArgs))]
|
||||
[EventHandler("onfullscreenerror", typeof(EventArgs))]
|
||||
[EventHandler("onloadeddata", typeof(EventArgs))]
|
||||
[EventHandler("onloadedmetadata", typeof(EventArgs))]
|
||||
[EventHandler("onpointerlockchange", typeof(EventArgs))]
|
||||
[EventHandler("onpointerlockerror", typeof(EventArgs))]
|
||||
[EventHandler("onreadystatechange", typeof(EventArgs))]
|
||||
[EventHandler("onscroll", typeof(EventArgs))]
|
||||
[EventHandler("onactivate", typeof(EventArgs), true, true)]
|
||||
[EventHandler("onbeforeactivate", typeof(EventArgs), true, true)]
|
||||
[EventHandler("onbeforedeactivate", typeof(EventArgs), true, true)]
|
||||
[EventHandler("ondeactivate", typeof(EventArgs), true, true)]
|
||||
[EventHandler("onended", typeof(EventArgs), true, true)]
|
||||
[EventHandler("onfullscreenchange", typeof(EventArgs), true, true)]
|
||||
[EventHandler("onfullscreenerror", typeof(EventArgs), true, true)]
|
||||
[EventHandler("onloadeddata", typeof(EventArgs), true, true)]
|
||||
[EventHandler("onloadedmetadata", typeof(EventArgs), true, true)]
|
||||
[EventHandler("onpointerlockchange", typeof(EventArgs), true, true)]
|
||||
[EventHandler("onpointerlockerror", typeof(EventArgs), true, true)]
|
||||
[EventHandler("onreadystatechange", typeof(EventArgs), true, true)]
|
||||
[EventHandler("onscroll", typeof(EventArgs), true, true)]
|
||||
public static class EventHandlers
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests
|
|||
{
|
||||
// Arrange
|
||||
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()
|
||||
{
|
||||
|
|
@ -65,7 +65,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests
|
|||
{
|
||||
// Arrange
|
||||
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()
|
||||
{
|
||||
|
|
@ -105,7 +105,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests
|
|||
{
|
||||
// Arrange
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -216,7 +216,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests
|
|||
{
|
||||
// Arrange
|
||||
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.";
|
||||
|
||||
var rootUri = ServerFixture.RootUri;
|
||||
|
|
@ -245,7 +245,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests
|
|||
{
|
||||
// Arrange
|
||||
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.";
|
||||
|
||||
var rootUri = ServerFixture.RootUri;
|
||||
|
|
|
|||
|
|
@ -75,11 +75,6 @@ namespace Microsoft.AspNetCore.Components
|
|||
|
||||
async Task IAsyncLifetime.DisposeAsync()
|
||||
{
|
||||
if (TestSink != null)
|
||||
{
|
||||
TestSink.MessageLogged -= TestSink_MessageLogged;
|
||||
}
|
||||
|
||||
await DisposeAsync();
|
||||
}
|
||||
|
||||
|
|
@ -90,6 +85,11 @@ namespace Microsoft.AspNetCore.Components
|
|||
|
||||
protected virtual Task DisposeAsync()
|
||||
{
|
||||
if (TestSink != null)
|
||||
{
|
||||
TestSink.MessageLogged -= TestSink_MessageLogged;
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
|
|
@ -97,7 +97,18 @@ namespace Microsoft.AspNetCore.Components
|
|||
{
|
||||
var log = new LogMessage(context.LogLevel, context.EventId, context.Message, context.Exception);
|
||||
Logs.Enqueue(log);
|
||||
Output.WriteLine(log.ToString());
|
||||
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());
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[DebuggerDisplay("{LogLevel.ToString(),nq} - {Message ?? \"null\",nq} - {Exception?.Message,nq}")]
|
||||
|
|
|
|||
|
|
@ -1,18 +1,17 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using BasicTestApp;
|
||||
using BasicTestApp.FormsTest;
|
||||
using Microsoft.AspNetCore.Components.E2ETest.Infrastructure;
|
||||
using Microsoft.AspNetCore.Components.E2ETest.Infrastructure.ServerFixtures;
|
||||
using Microsoft.AspNetCore.E2ETesting;
|
||||
using Microsoft.AspNetCore.Testing;
|
||||
using OpenQA.Selenium;
|
||||
using OpenQA.Selenium.Support.UI;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
|
|
@ -34,14 +33,20 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
|
|||
Navigate(ServerPathBase, noReload: _serverFixture.ExecutionMode == ExecutionMode.Client);
|
||||
}
|
||||
|
||||
protected virtual IWebElement MountSimpleValidationComponent()
|
||||
=> Browser.MountTestComponent<SimpleValidationComponent>();
|
||||
|
||||
protected virtual IWebElement MountTypicalValidationComponent()
|
||||
=> Browser.MountTestComponent<TypicalValidationComponent>();
|
||||
|
||||
[Fact]
|
||||
public async Task EditFormWorksWithDataAnnotationsValidator()
|
||||
{
|
||||
var appElement = Browser.MountTestComponent<SimpleValidationComponent>();
|
||||
var appElement = MountSimpleValidationComponent();;
|
||||
var form = appElement.FindElement(By.TagName("form"));
|
||||
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 submitButton = appElement.FindElement(By.TagName("button"));
|
||||
var submitButton = appElement.FindElement(By.CssSelector("button[type=submit]"));
|
||||
var messagesAccessor = CreateValidationMessagesAccessor(appElement);
|
||||
|
||||
// The form emits unmatched attributes
|
||||
|
|
@ -77,7 +82,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
|
|||
[Fact]
|
||||
public void InputTextInteractsWithEditContext()
|
||||
{
|
||||
var appElement = Browser.MountTestComponent<TypicalValidationComponent>();
|
||||
var appElement = MountTypicalValidationComponent();
|
||||
var nameInput = appElement.FindElement(By.ClassName("name")).FindElement(By.TagName("input"));
|
||||
var messagesAccessor = CreateValidationMessagesAccessor(appElement);
|
||||
|
||||
|
|
@ -104,7 +109,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
|
|||
[Fact]
|
||||
public void InputNumberInteractsWithEditContext_NonNullableInt()
|
||||
{
|
||||
var appElement = Browser.MountTestComponent<TypicalValidationComponent>();
|
||||
var appElement = MountTypicalValidationComponent();
|
||||
var ageInput = appElement.FindElement(By.ClassName("age")).FindElement(By.TagName("input"));
|
||||
var messagesAccessor = CreateValidationMessagesAccessor(appElement);
|
||||
|
||||
|
|
@ -136,7 +141,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
|
|||
[Fact]
|
||||
public void InputNumberInteractsWithEditContext_NullableFloat()
|
||||
{
|
||||
var appElement = Browser.MountTestComponent<TypicalValidationComponent>();
|
||||
var appElement = MountTypicalValidationComponent();
|
||||
var heightInput = appElement.FindElement(By.ClassName("height")).FindElement(By.TagName("input"));
|
||||
var messagesAccessor = CreateValidationMessagesAccessor(appElement);
|
||||
|
||||
|
|
@ -160,7 +165,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
|
|||
[Fact]
|
||||
public void InputTextAreaInteractsWithEditContext()
|
||||
{
|
||||
var appElement = Browser.MountTestComponent<TypicalValidationComponent>();
|
||||
var appElement = MountTypicalValidationComponent();
|
||||
var descriptionInput = appElement.FindElement(By.ClassName("description")).FindElement(By.TagName("textarea"));
|
||||
var messagesAccessor = CreateValidationMessagesAccessor(appElement);
|
||||
|
||||
|
|
@ -187,7 +192,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
|
|||
[Fact]
|
||||
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 messagesAccessor = CreateValidationMessagesAccessor(appElement);
|
||||
|
||||
|
|
@ -218,7 +223,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
|
|||
[Fact]
|
||||
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 messagesAccessor = CreateValidationMessagesAccessor(appElement);
|
||||
|
||||
|
|
@ -241,7 +246,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
|
|||
[Fact]
|
||||
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 select = ticketClassInput.WrappedElement;
|
||||
var messagesAccessor = CreateValidationMessagesAccessor(appElement);
|
||||
|
|
@ -263,7 +268,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
|
|||
[Fact]
|
||||
public void InputCheckboxInteractsWithEditContext()
|
||||
{
|
||||
var appElement = Browser.MountTestComponent<TypicalValidationComponent>();
|
||||
var appElement = MountTypicalValidationComponent();
|
||||
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 messagesAccessor = CreateValidationMessagesAccessor(appElement);
|
||||
|
|
@ -297,7 +302,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
|
|||
var appElement = Browser.MountTestComponent<NotifyPropertyChangedValidationComponent>();
|
||||
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 submitButton = appElement.FindElement(By.TagName("button"));
|
||||
var submitButton = appElement.FindElement(By.CssSelector("button[type=submit]"));
|
||||
var messagesAccessor = CreateValidationMessagesAccessor(appElement);
|
||||
var submissionStatus = appElement.FindElement(By.Id("submission-status"));
|
||||
|
||||
|
|
@ -331,11 +336,11 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
|
|||
[Fact]
|
||||
public void ValidationMessageDisplaysMessagesForField()
|
||||
{
|
||||
var appElement = Browser.MountTestComponent<TypicalValidationComponent>();
|
||||
var appElement = MountTypicalValidationComponent();
|
||||
var emailContainer = appElement.FindElement(By.ClassName("email"));
|
||||
var emailInput = emailContainer.FindElement(By.TagName("input"));
|
||||
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
|
||||
submitButton.Click();
|
||||
|
|
@ -355,10 +360,43 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
|
|||
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]
|
||||
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 selectedTicketClassDisplay = appElement.FindElement(By.Id("selected-ticket-class"));
|
||||
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.HttpClient" />
|
||||
<Reference Include="Microsoft.AspNetCore.Components.Authorization" />
|
||||
<Reference Include="Microsoft.AspNetCore.Blazor.DataAnnotations.Validation" />
|
||||
</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
|
||||
|
||||
<EditForm Model="@this" OnValidSubmit="@HandleValidSubmit" OnInvalidSubmit="@HandleInvalidSubmit" autocomplete="off">
|
||||
<DataAnnotationsValidator />
|
||||
@if (UseExperimentalValidator)
|
||||
{
|
||||
<ObjectGraphDataAnnotationsValidator />
|
||||
}
|
||||
else
|
||||
{
|
||||
<DataAnnotationsValidator />
|
||||
}
|
||||
|
||||
<p class="user-name">
|
||||
User name: <input @bind="UserName" class="@context.FieldCssClass(() => UserName)" />
|
||||
|
|
@ -29,6 +36,8 @@
|
|||
}
|
||||
|
||||
@code {
|
||||
protected virtual bool UseExperimentalValidator => false;
|
||||
|
||||
string lastCallback;
|
||||
|
||||
[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
|
||||
|
||||
<EditForm EditContext="@editContext" OnValidSubmit="@HandleValidSubmit">
|
||||
@if (UseExperimentalValidator)
|
||||
{
|
||||
<ObjectGraphDataAnnotationsValidator />
|
||||
}
|
||||
else
|
||||
{
|
||||
<DataAnnotationsValidator />
|
||||
}
|
||||
|
||||
<p class="name">
|
||||
Name: <InputText @bind-Value="person.Name" placeholder="Enter your name" />
|
||||
|
|
@ -11,6 +18,10 @@
|
|||
Email: <InputText @bind-Value="person.Email" />
|
||||
<ValidationMessage For="@(() => person.Email)" />
|
||||
</p>
|
||||
<p class="confirm-email">
|
||||
Email: <InputText @bind-Value="person.ConfirmEmail" />
|
||||
<ValidationMessage For="@(() => person.ConfirmEmail)" />
|
||||
</p>
|
||||
<p class="age">
|
||||
Age (years): <InputNumber @bind-Value="person.AgeInYears" placeholder="Enter your age" />
|
||||
</p>
|
||||
|
|
@ -49,12 +60,18 @@
|
|||
|
||||
<button type="submit">Submit</button>
|
||||
|
||||
<p class="model-errors">
|
||||
<ValidationSummary Model="person" />
|
||||
</p>
|
||||
|
||||
<ValidationSummary />
|
||||
</EditForm>
|
||||
|
||||
<ul>@foreach (var entry in submissionLog) { <li>@entry</li> }</ul>
|
||||
|
||||
@code {
|
||||
protected virtual bool UseExperimentalValidator => false;
|
||||
|
||||
Person person = new Person();
|
||||
EditContext editContext;
|
||||
ValidationMessageStore customValidationMessageStore;
|
||||
|
|
@ -75,6 +92,9 @@
|
|||
[StringLength(10, ErrorMessage = "We only accept very short email addresses (max 10 chars)")]
|
||||
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")]
|
||||
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.FormsTest.NotifyPropertyChangedValidationComponent">INotifyPropertyChanged 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.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.HierarchicalImportsTest.Subdir.ComponentUsingImports">Imports statement</option>
|
||||
<option value="BasicTestApp.HtmlBlockChildContent">ChildContent HTML Block</option>
|
||||
|
|
|
|||
|
|
@ -4,6 +4,16 @@ html, body {
|
|||
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
}
|
||||
|
||||
a, .btn-link {
|
||||
color: #0366d6;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
color: #fff;
|
||||
background-color: #1b6ec2;
|
||||
border-color: #1861ac;
|
||||
}
|
||||
|
||||
app {
|
||||
position: relative;
|
||||
display: flex;
|
||||
|
|
@ -21,10 +31,21 @@ app {
|
|||
}
|
||||
|
||||
.main .top-row {
|
||||
background-color: #e6e6e6;
|
||||
background-color: #f7f7f7;
|
||||
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 {
|
||||
background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%);
|
||||
}
|
||||
|
|
@ -44,38 +65,38 @@ app {
|
|||
top: -2px;
|
||||
}
|
||||
|
||||
.nav-item {
|
||||
font-size: 0.9rem;
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.nav-item:first-of-type {
|
||||
padding-top: 1rem;
|
||||
.sidebar .nav-item {
|
||||
font-size: 0.9rem;
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.nav-item:last-of-type {
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
|
||||
.nav-item a {
|
||||
color: #d7d7d7;
|
||||
border-radius: 4px;
|
||||
height: 3rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
line-height: 3rem;
|
||||
}
|
||||
|
||||
.nav-item a.active {
|
||||
background-color: rgba(255,255,255,0.25);
|
||||
color: white;
|
||||
.sidebar .nav-item:first-of-type {
|
||||
padding-top: 1rem;
|
||||
}
|
||||
|
||||
.nav-item a:hover {
|
||||
background-color: rgba(255,255,255,0.1);
|
||||
color: white;
|
||||
.sidebar .nav-item:last-of-type {
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
|
||||
.sidebar .nav-item a {
|
||||
color: #d7d7d7;
|
||||
border-radius: 4px;
|
||||
height: 3rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
line-height: 3rem;
|
||||
}
|
||||
|
||||
.sidebar .nav-item a.active {
|
||||
background-color: rgba(255,255,255,0.25);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.sidebar .nav-item a:hover {
|
||||
background-color: rgba(255,255,255,0.1);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.content {
|
||||
padding-top: 1.1rem;
|
||||
}
|
||||
|
|
@ -96,10 +117,37 @@ app {
|
|||
color: red;
|
||||
}
|
||||
|
||||
#blazor-error-ui {
|
||||
background: lightyellow;
|
||||
bottom: 0;
|
||||
box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
|
||||
display: none;
|
||||
left: 0;
|
||||
padding: 0.6rem 1.25rem 0.7rem 1.25rem;
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
#blazor-error-ui .dismiss {
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
right: 0.75rem;
|
||||
top: 0.5rem;
|
||||
}
|
||||
|
||||
@media (max-width: 767.98px) {
|
||||
.main .top-row {
|
||||
.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;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
|
|
|
|||
|
|
@ -24,17 +24,15 @@ namespace Microsoft.AspNetCore.Hosting.FunctionalTests
|
|||
|
||||
public ShutdownTests(ITestOutputHelper output) : base(output) { }
|
||||
|
||||
[ConditionalFact(Skip = "https://github.com/aspnet/AspNetCore-Internal/issues/2577")]
|
||||
[ConditionalFact]
|
||||
[OSSkipCondition(OperatingSystems.Windows)]
|
||||
[OSSkipCondition(OperatingSystems.MacOSX)]
|
||||
[Flaky("https://github.com/aspnet/AspNetCore-Internal/issues/2577", FlakyOn.All)]
|
||||
public async Task ShutdownTestRun()
|
||||
{
|
||||
await ExecuteShutdownTest(nameof(ShutdownTestRun), "Run");
|
||||
}
|
||||
|
||||
[ConditionalFact]
|
||||
[Flaky("https://github.com/aspnet/Hosting/issues/1214", FlakyOn.All)]
|
||||
[OSSkipCondition(OperatingSystems.Windows)]
|
||||
[OSSkipCondition(OperatingSystems.MacOSX)]
|
||||
public async Task ShutdownTestWaitForShutdown()
|
||||
|
|
|
|||
|
|
@ -167,7 +167,7 @@ namespace Microsoft.AspNetCore.WebUtilities
|
|||
if (!isFinalBlock)
|
||||
{
|
||||
// Don't buffer indefinately
|
||||
if (span.Length > KeyLengthLimit + ValueLengthLimit)
|
||||
if ((uint)span.Length > (uint)KeyLengthLimit + (uint)ValueLengthLimit)
|
||||
{
|
||||
ThrowKeyOrValueTooLargeException();
|
||||
}
|
||||
|
|
@ -236,7 +236,7 @@ namespace Microsoft.AspNetCore.WebUtilities
|
|||
if (!isFinalBlock)
|
||||
{
|
||||
// Don't buffer indefinately
|
||||
if ((sequenceReader.Consumed - consumedBytes) > KeyLengthLimit + ValueLengthLimit)
|
||||
if ((uint)(sequenceReader.Consumed - consumedBytes) > (uint)KeyLengthLimit + (uint)ValueLengthLimit)
|
||||
{
|
||||
ThrowKeyOrValueTooLargeException();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -211,6 +211,28 @@ namespace Microsoft.AspNetCore.WebUtilities
|
|||
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]
|
||||
[MemberData(nameof(Encodings))]
|
||||
public void TryParseFormValues_SplitAcrossSegmentsWorks(Encoding encoding)
|
||||
|
|
@ -230,6 +252,28 @@ namespace Microsoft.AspNetCore.WebUtilities
|
|||
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]
|
||||
[MemberData(nameof(Encodings))]
|
||||
public void TryParseFormValues_MultiSegmentWithArrayPoolAcrossSegmentsWorks(Encoding encoding)
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ namespace Microsoft.AspNetCore.Identity
|
|||
{
|
||||
var key = await manager.GetAuthenticatorKeyAsync(user);
|
||||
int code;
|
||||
if (!int.TryParse(token, out code))
|
||||
if (key == null || !int.TryParse(token, out code))
|
||||
{
|
||||
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 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> OnPostSendVerificationEmailAsync() { throw null; }
|
||||
public partial class 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 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 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]
|
||||
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 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 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]
|
||||
public abstract partial class RegisterModel : Microsoft.AspNetCore.Mvc.RazorPages.PageModel
|
||||
|
|
|
|||
|
|
@ -41,9 +41,6 @@
|
|||
<p>
|
||||
<a asp-page="./Register" asp-route-returnUrl="@Model.ReturnUrl">Register as a new user</a>
|
||||
</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>
|
||||
</form>
|
||||
</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.
|
||||
/// </summary>
|
||||
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
|
||||
|
|
@ -105,15 +99,12 @@ namespace Microsoft.AspNetCore.Identity.UI.V3.Pages.Account.Internal
|
|||
private readonly UserManager<TUser> _userManager;
|
||||
private readonly SignInManager<TUser> _signInManager;
|
||||
private readonly ILogger<LoginModel> _logger;
|
||||
private readonly IEmailSender _emailSender;
|
||||
|
||||
public LoginModel(SignInManager<TUser> signInManager, ILogger<LoginModel> logger,
|
||||
UserManager<TUser> userManager,
|
||||
IEmailSender emailSender)
|
||||
UserManager<TUser> userManager)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_signInManager = signInManager;
|
||||
_emailSender = emailSender;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
|
|
@ -169,34 +160,5 @@ namespace Microsoft.AspNetCore.Identity.UI.V3.Pages.Account.Internal
|
|||
// If we got this far, something failed, redisplay form
|
||||
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(
|
||||
"/Account/ConfirmEmail",
|
||||
pageHandler: null,
|
||||
values: new { area = "Identity", userId = userId, code = code },
|
||||
values: new { area = "Identity", userId = userId, code = code, returnUrl = returnUrl },
|
||||
protocol: Request.Scheme);
|
||||
|
||||
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)
|
||||
{
|
||||
return RedirectToPage("RegisterConfirmation", new { email = Input.Email });
|
||||
return RedirectToPage("RegisterConfirmation", new { email = Input.Email, returnUrl = returnUrl });
|
||||
}
|
||||
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
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </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
|
||||
|
|
@ -57,12 +57,13 @@ namespace Microsoft.AspNetCore.Identity.UI.V3.Pages.Account.Internal
|
|||
_sender = sender;
|
||||
}
|
||||
|
||||
public override async Task<IActionResult> OnGetAsync(string email)
|
||||
public override async Task<IActionResult> OnGetAsync(string email, string returnUrl = null)
|
||||
{
|
||||
if (email == null)
|
||||
{
|
||||
return RedirectToPage("/Index");
|
||||
}
|
||||
returnUrl = returnUrl ?? Url.Content("~/");
|
||||
|
||||
var user = await _userManager.FindByEmailAsync(email);
|
||||
if (user == null)
|
||||
|
|
@ -81,7 +82,7 @@ namespace Microsoft.AspNetCore.Identity.UI.V3.Pages.Account.Internal
|
|||
EmailConfirmationUrl = Url.Page(
|
||||
"/Account/ConfirmEmail",
|
||||
pageHandler: null,
|
||||
values: new { area = "Identity", userId = userId, code = code },
|
||||
values: new { area = "Identity", userId = userId, code = code, returnUrl = returnUrl },
|
||||
protocol: Request.Scheme);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -146,7 +146,7 @@ namespace Microsoft.AspNetCore.Identity.UI.V4.Pages.Account.Internal
|
|||
var callbackUrl = Url.Page(
|
||||
"/Account/ConfirmEmail",
|
||||
pageHandler: null,
|
||||
values: new { area = "Identity", userId = userId, code = code },
|
||||
values: new { area = "Identity", userId = userId, code = code, returnUrl = returnUrl },
|
||||
protocol: Request.Scheme);
|
||||
|
||||
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)
|
||||
{
|
||||
return RedirectToPage("RegisterConfirmation", new { email = Input.Email });
|
||||
return RedirectToPage("RegisterConfirmation", new { email = Input.Email, returnUrl = returnUrl });
|
||||
}
|
||||
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
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </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
|
||||
|
|
@ -57,12 +57,13 @@ namespace Microsoft.AspNetCore.Identity.UI.V4.Pages.Account.Internal
|
|||
_sender = sender;
|
||||
}
|
||||
|
||||
public override async Task<IActionResult> OnGetAsync(string email)
|
||||
public override async Task<IActionResult> OnGetAsync(string email, string returnUrl = null)
|
||||
{
|
||||
if (email == null)
|
||||
{
|
||||
return RedirectToPage("/Index");
|
||||
}
|
||||
returnUrl = returnUrl ?? Url.Content("~/");
|
||||
|
||||
var user = await _userManager.FindByEmailAsync(email);
|
||||
if (user == null)
|
||||
|
|
@ -81,7 +82,7 @@ namespace Microsoft.AspNetCore.Identity.UI.V4.Pages.Account.Internal
|
|||
EmailConfirmationUrl = Url.Page(
|
||||
"/Account/ConfirmEmail",
|
||||
pageHandler: null,
|
||||
values: new { area = "Identity", userId = userId, code = code },
|
||||
values: new { area = "Identity", userId = userId, code = code, returnUrl = returnUrl },
|
||||
protocol: Request.Scheme);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -56,12 +56,13 @@
|
|||
</div>
|
||||
<footer class="footer border-top pl-3 text-muted">
|
||||
<div class="container">
|
||||
© @DateTime.Now.Year - @Environment.ApplicationName -
|
||||
© @DateTime.Now.Year - @Environment.ApplicationName
|
||||
@{
|
||||
var foundPrivacy = Url.Page("/Privacy", new { area = "" });
|
||||
}
|
||||
@if (foundPrivacy != null)
|
||||
{
|
||||
@:-
|
||||
<a asp-area="" asp-page="/Privacy">Privacy</a>
|
||||
}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests.Account
|
|||
});
|
||||
|
||||
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 register = await ResponseAssert.IsHtmlDocumentAsync(registerResponse);
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,8 @@
|
|||
<Target Name="Build" DependsOnTargets="DebBuild" />
|
||||
<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 -->
|
||||
<PropertyGroup>
|
||||
<DebianConfigProperties>
|
||||
|
|
|
|||
|
|
@ -32,7 +32,8 @@
|
|||
<Target Name="Build" DependsOnTargets="RpmBuild" />
|
||||
<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 -->
|
||||
<PropertyGroup>
|
||||
<ChangeLogProps>DATE=$([System.DateTime]::UtcNow.ToString(ddd MMM dd yyyy))</ChangeLogProps>
|
||||
|
|
|
|||
|
|
@ -82,7 +82,8 @@
|
|||
<BuildDependsOn Condition="'$(IsTargetingPackBuilding)' == 'false'" />
|
||||
</PropertyGroup>
|
||||
|
||||
<Target Name="CreateTargetingPackNugetPackage" AfterTargets="CopyToArtifactsDirectory;Build">
|
||||
<Target Name="CreateTargetingPackNugetPackage" AfterTargets="CopyToArtifactsDirectory;Build"
|
||||
Condition="'$(IsTargetingPackBuilding)' != 'false'">
|
||||
<PropertyGroup>
|
||||
<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 System.Type ModelType { [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 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, 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 ForType(System.Type modelType) { throw null; }
|
||||
public override int GetHashCode() { throw null; }
|
||||
|
|
|
|||
|
|
@ -17,12 +17,12 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
|||
Type modelType,
|
||||
string name = null,
|
||||
Type containerType = null,
|
||||
ParameterInfo parameterInfo = null)
|
||||
object fieldInfo = null)
|
||||
{
|
||||
ModelType = modelType;
|
||||
Name = name;
|
||||
ContainerType = containerType;
|
||||
ParameterInfo = parameterInfo;
|
||||
FieldInfo = fieldInfo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -47,6 +47,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
|||
/// <param name="name">The name of the property.</param>
|
||||
/// <param name="containerType">The container type of the model property.</param>
|
||||
/// <returns>A <see cref="ModelMetadataIdentity"/>.</returns>
|
||||
[Obsolete("This API is obsolete and may be removed in a future release.")]
|
||||
public static ModelMetadataIdentity ForProperty(
|
||||
Type modelType,
|
||||
string name,
|
||||
|
|
@ -70,6 +71,36 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
|||
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>
|
||||
/// Creates a <see cref="ModelMetadataIdentity"/> for the provided parameter.
|
||||
/// </summary>
|
||||
|
|
@ -97,7 +128,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
|||
throw new ArgumentNullException(nameof(modelType));
|
||||
}
|
||||
|
||||
return new ModelMetadataIdentity(modelType, parameter.Name, parameterInfo: parameter);
|
||||
return new ModelMetadataIdentity(modelType, parameter.Name, fieldInfo: parameter);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -139,11 +170,19 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
|||
/// </summary>
|
||||
public string Name { get; }
|
||||
|
||||
private object FieldInfo { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a descriptor for the parameter, or <c>null</c> if this instance
|
||||
/// does not represent a parameter.
|
||||
/// </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 />
|
||||
public bool Equals(ModelMetadataIdentity other)
|
||||
|
|
@ -152,7 +191,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
|||
ContainerType == other.ContainerType &&
|
||||
ModelType == other.ModelType &&
|
||||
Name == other.Name &&
|
||||
ParameterInfo == other.ParameterInfo;
|
||||
ParameterInfo == other.ParameterInfo &&
|
||||
PropertyInfo == other.PropertyInfo;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
|
@ -170,6 +210,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
|||
hash.Add(ModelType);
|
||||
hash.Add(Name, StringComparer.Ordinal);
|
||||
hash.Add(ParameterInfo);
|
||||
hash.Add(PropertyInfo);
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -270,7 +270,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
|||
public void ContainerType_ReturnExpectedMetadata_ForProperty()
|
||||
{
|
||||
// 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.Equal(typeof(string), metadata.ContainerType);
|
||||
|
|
@ -308,7 +309,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
|||
public void Names_ReturnExpectedMetadata_ForProperty()
|
||||
{
|
||||
// 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.Equal(nameof(string.Length), metadata.Name);
|
||||
|
|
@ -322,7 +324,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
|||
public void GetDisplayName_ReturnsDisplayName_IfSet()
|
||||
{
|
||||
// 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");
|
||||
|
||||
// Act
|
||||
|
|
@ -351,7 +354,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
|||
public void GetDisplayName_ReturnsPropertyName_WhenSetAndDisplayNameIsNull()
|
||||
{
|
||||
// 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
|
||||
var result = metadata.GetDisplayName();
|
||||
|
|
@ -419,8 +423,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
|||
{
|
||||
}
|
||||
|
||||
public TestModelMetadata(Type modelType, string propertyName, Type containerType)
|
||||
: base(ModelMetadataIdentity.ForProperty(modelType, propertyName, containerType))
|
||||
public TestModelMetadata(PropertyInfo propertyInfo, Type modelType, Type containerType)
|
||||
: base(ModelMetadataIdentity.ForProperty(propertyInfo, modelType, containerType))
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ using System.Text.Json;
|
|||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc.Formatters.Json;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||
|
|
@ -87,6 +86,16 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
|||
|
||||
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
|
||||
{
|
||||
if (inputStream is TranscodingReadStream transcoding)
|
||||
|
|
|
|||
|
|
@ -190,7 +190,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
|||
private ModelMetadataCacheEntry GetCacheEntry(PropertyInfo property, Type modelType)
|
||||
{
|
||||
return _typeCache.GetOrAdd(
|
||||
ModelMetadataIdentity.ForProperty(modelType, property.Name, property.DeclaringType),
|
||||
ModelMetadataIdentity.ForProperty(property, modelType, property.DeclaringType),
|
||||
_cacheEntryFactory);
|
||||
}
|
||||
|
||||
|
|
@ -275,8 +275,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
|||
var propertyHelper = propertyHelpers[i];
|
||||
|
||||
var propertyKey = ModelMetadataIdentity.ForProperty(
|
||||
propertyHelper.Property,
|
||||
propertyHelper.Property.PropertyType,
|
||||
propertyHelper.Name,
|
||||
key.ModelType);
|
||||
|
||||
var propertyEntry = CreateSinglePropertyDetails(propertyKey, propertyHelper);
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
|
@ -27,7 +25,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
|||
|
||||
var context = new DefaultModelBindingContext();
|
||||
|
||||
#pragma warning disable CS0618 // Type or member is obsolete
|
||||
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;
|
||||
|
||||
// Act
|
||||
|
|
|
|||
|
|
@ -334,7 +334,8 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
|||
// Assert
|
||||
Assert.True(result.HasError, "Model should have produced an error!");
|
||||
Assert.Collection(formatterContext.ModelState.OrderBy(k => k.Key),
|
||||
kvp => {
|
||||
kvp =>
|
||||
{
|
||||
Assert.Equal(expectedValue, kvp.Key);
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
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()
|
||||
{
|
||||
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_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(
|
||||
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));
|
||||
|
||||
var provider = new DefaultBindingMetadataProvider();
|
||||
|
|
@ -184,7 +184,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
|||
};
|
||||
|
||||
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));
|
||||
|
||||
var provider = new DefaultBindingMetadataProvider();
|
||||
|
|
@ -207,7 +207,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
|||
};
|
||||
|
||||
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));
|
||||
|
||||
var provider = new DefaultBindingMetadataProvider();
|
||||
|
|
@ -230,7 +230,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
|||
};
|
||||
|
||||
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));
|
||||
|
||||
var provider = new DefaultBindingMetadataProvider();
|
||||
|
|
@ -253,7 +253,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
|||
};
|
||||
|
||||
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));
|
||||
|
||||
var provider = new DefaultBindingMetadataProvider();
|
||||
|
|
@ -420,7 +420,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
|||
};
|
||||
|
||||
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));
|
||||
|
||||
var provider = new DefaultBindingMetadataProvider();
|
||||
|
|
@ -438,7 +438,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
|||
{
|
||||
// Arrange
|
||||
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));
|
||||
|
||||
var provider = new DefaultBindingMetadataProvider();
|
||||
|
|
@ -456,7 +456,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
|||
{
|
||||
// Arrange
|
||||
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));
|
||||
|
||||
var provider = new DefaultBindingMetadataProvider();
|
||||
|
|
@ -474,7 +474,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
|||
{
|
||||
// Arrange
|
||||
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));
|
||||
|
||||
var provider = new DefaultBindingMetadataProvider();
|
||||
|
|
@ -497,7 +497,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
|||
};
|
||||
|
||||
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));
|
||||
|
||||
var provider = new DefaultBindingMetadataProvider();
|
||||
|
|
@ -520,7 +520,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
|||
};
|
||||
|
||||
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));
|
||||
|
||||
var provider = new DefaultBindingMetadataProvider();
|
||||
|
|
@ -543,7 +543,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
|||
};
|
||||
|
||||
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));
|
||||
|
||||
var provider = new DefaultBindingMetadataProvider();
|
||||
|
|
@ -566,7 +566,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
|||
};
|
||||
|
||||
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));
|
||||
|
||||
var provider = new DefaultBindingMetadataProvider();
|
||||
|
|
@ -585,7 +585,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
|||
{
|
||||
// Arrange
|
||||
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));
|
||||
|
||||
var provider = new DefaultBindingMetadataProvider();
|
||||
|
|
@ -641,7 +641,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
|||
};
|
||||
|
||||
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));
|
||||
|
||||
// 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 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));
|
||||
|
||||
// Act
|
||||
|
|
@ -123,8 +123,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
|||
var detailsProvider = new EmptyCompositeMetadataDetailsProvider();
|
||||
|
||||
var key = ModelMetadataIdentity.ForProperty(
|
||||
typeof(TypeWithProperties).GetProperty(nameof(TypeWithProperties.PublicGetPublicSetProperty)),
|
||||
typeof(string),
|
||||
nameof(TypeWithProperties.PublicGetPublicSetProperty),
|
||||
typeof(TypeWithProperties));
|
||||
|
||||
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 key = ModelMetadataIdentity.ForProperty(
|
||||
typeof(TypeWithProperties).GetProperty(nameof(TypeWithProperties.PublicGetPublicSetProperty)),
|
||||
typeof(string),
|
||||
nameof(TypeWithProperties.PublicGetPublicSetProperty),
|
||||
typeof(TypeWithProperties));
|
||||
|
||||
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 key = ModelMetadataIdentity.ForProperty(
|
||||
typeof(TypeWithProperties).GetProperty(nameof(TypeWithProperties.PublicGetPublicSetProperty)),
|
||||
typeof(string),
|
||||
nameof(TypeWithProperties.PublicGetPublicSetProperty),
|
||||
typeof(TypeWithProperties));
|
||||
|
||||
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 detailsProvider = new EmptyCompositeMetadataDetailsProvider();
|
||||
|
||||
var prop1 = typeof(Exception).GetProperty(nameof(Exception.Message));
|
||||
var prop2 = typeof(Exception).GetProperty(nameof(Exception.StackTrace));
|
||||
|
||||
var expectedProperties = new DefaultModelMetadata[]
|
||||
{
|
||||
new DefaultModelMetadata(
|
||||
provider.Object,
|
||||
detailsProvider,
|
||||
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))),
|
||||
new DefaultModelMetadata(
|
||||
provider.Object,
|
||||
detailsProvider,
|
||||
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))),
|
||||
};
|
||||
|
||||
|
|
@ -475,7 +478,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
|||
provider.Object,
|
||||
detailsProvider,
|
||||
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)),
|
||||
#pragma warning restore CS0618 // Type or member is obsolete
|
||||
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)
|
||||
{
|
||||
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)),
|
||||
#pragma warning restore CS0618 // Type or member is obsolete
|
||||
attributes: new ModelAttributes(new object[0], new object[0], null))
|
||||
{
|
||||
DisplayMetadata = new DisplayMetadata(),
|
||||
|
|
@ -934,7 +941,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
|||
// Arrange
|
||||
var property = GetType()
|
||||
.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);
|
||||
|
||||
// Act
|
||||
|
|
@ -997,7 +1004,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
|||
var metadataProvider = new Mock<IModelMetadataProvider>();
|
||||
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);
|
||||
|
||||
metadataProvider
|
||||
|
|
@ -1021,10 +1029,10 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
|||
var metadataProvider = new Mock<IModelMetadataProvider>();
|
||||
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 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);
|
||||
|
||||
metadataProvider
|
||||
|
|
@ -1048,7 +1056,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
|||
var metadataProvider = new Mock<IModelMetadataProvider>();
|
||||
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);
|
||||
|
||||
metadataProvider
|
||||
|
|
@ -1072,10 +1080,10 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
|||
var metadataProvider = new Mock<IModelMetadataProvider>();
|
||||
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 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);
|
||||
|
||||
metadataProvider
|
||||
|
|
@ -1099,18 +1107,19 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
|||
var metadataProvider = new Mock<IModelMetadataProvider>();
|
||||
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 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 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 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 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 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.
|
||||
|
||||
metadataProvider
|
||||
|
|
@ -1139,18 +1148,19 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
|||
var metadataProvider = new Mock<IModelMetadataProvider>();
|
||||
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 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 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 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 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 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);
|
||||
|
||||
metadataProvider
|
||||
|
|
@ -1181,9 +1191,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
|||
var metadataProvider = new Mock<IModelMetadataProvider>();
|
||||
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 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);
|
||||
|
||||
metadataProvider
|
||||
|
|
@ -1210,18 +1220,19 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
|||
var metadataProvider = new Mock<IModelMetadataProvider>();
|
||||
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 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 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 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 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 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);
|
||||
|
||||
metadataProvider
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
|||
var provider = new DefaultValidationMetadataProvider();
|
||||
|
||||
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));
|
||||
|
||||
// Act
|
||||
|
|
@ -37,7 +37,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
|||
var provider = new DefaultValidationMetadataProvider();
|
||||
|
||||
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));
|
||||
|
||||
// Act
|
||||
|
|
@ -71,8 +71,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
|||
var provider = new DefaultValidationMetadataProvider();
|
||||
|
||||
var key = ModelMetadataIdentity.ForProperty(
|
||||
typeof(ValidateNeverClass).GetProperty(nameof(ValidateNeverClass.ClassName)),
|
||||
typeof(string),
|
||||
nameof(ValidateNeverClass.ClassName),
|
||||
typeof(ValidateNeverClass));
|
||||
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 key = ModelMetadataIdentity.ForProperty(
|
||||
typeof(ValidateNeverSubclass).GetProperty(nameof(ValidateNeverSubclass.SubclassName)),
|
||||
typeof(string),
|
||||
nameof(ValidateNeverSubclass.SubclassName),
|
||||
typeof(ValidateNeverSubclass));
|
||||
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 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));
|
||||
|
||||
// Act
|
||||
|
|
@ -135,7 +135,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
|||
|
||||
var attribute = new TestModelValidationAttribute();
|
||||
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));
|
||||
|
||||
// Act
|
||||
|
|
@ -154,7 +154,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
|||
|
||||
var attribute = new TestValidationAttribute();
|
||||
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));
|
||||
context.ValidationMetadata.ValidatorMetadata.Add(attribute);
|
||||
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
|||
var provider = new ExcludeBindingMetadataProvider(typeof(string));
|
||||
|
||||
var key = ModelMetadataIdentity.ForProperty(
|
||||
typeof(Person).GetProperty(nameof(Person.Age)),
|
||||
typeof(int),
|
||||
nameof(Person.Age),
|
||||
typeof(Person));
|
||||
|
||||
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 key = ModelMetadataIdentity.ForProperty(
|
||||
typeof(Person).GetProperty(nameof(Person.Age)),
|
||||
typeof(int),
|
||||
nameof(Person.Age),
|
||||
typeof(Person));
|
||||
|
||||
var context = new BindingMetadataProviderContext(key, new ModelAttributes(new object[0], new object[0], null));
|
||||
|
|
|
|||
|
|
@ -366,10 +366,27 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations
|
|||
}
|
||||
else if (context.Key.MetadataKind == ModelMetadataKind.Property)
|
||||
{
|
||||
addInferredRequiredAttribute = IsNullableReferenceType(
|
||||
context.Key.ContainerType,
|
||||
member: null,
|
||||
context.PropertyAttributes);
|
||||
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(
|
||||
property.DeclaringType,
|
||||
member: null,
|
||||
context.PropertyAttributes);
|
||||
}
|
||||
}
|
||||
else if (context.Key.MetadataKind == ModelMetadataKind.Parameter)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -599,13 +599,13 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations
|
|||
provider.CreateDisplayMetadata(context);
|
||||
|
||||
// Assert
|
||||
using(new CultureReplacer("en-US", "en-US"))
|
||||
using (new CultureReplacer("en-US", "en-US"))
|
||||
{
|
||||
Assert.Equal("name from localizer en-US", context.DisplayMetadata.DisplayName());
|
||||
Assert.Equal("description from localizer en-US", context.DisplayMetadata.Description());
|
||||
Assert.Equal("prompt from localizer en-US", context.DisplayMetadata.Placeholder());
|
||||
}
|
||||
using(new CultureReplacer("fr-FR", "fr-FR"))
|
||||
using (new CultureReplacer("fr-FR", "fr-FR"))
|
||||
{
|
||||
Assert.Equal("name from localizer fr-FR", context.DisplayMetadata.DisplayName());
|
||||
Assert.Equal("description from localizer fr-FR", context.DisplayMetadata.Description());
|
||||
|
|
@ -1031,12 +1031,12 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations
|
|||
// Assert
|
||||
var groupTwo = Assert.Single(enumNameAndGroup, e => e.Value.Equals("2", StringComparison.Ordinal));
|
||||
|
||||
using(new CultureReplacer("en-US", "en-US"))
|
||||
using (new CultureReplacer("en-US", "en-US"))
|
||||
{
|
||||
Assert.Equal("Loc_Two_Name", groupTwo.Key.Name);
|
||||
}
|
||||
|
||||
using(new CultureReplacer("fr-FR", "fr-FR"))
|
||||
using (new CultureReplacer("fr-FR", "fr-FR"))
|
||||
{
|
||||
Assert.Equal("Loc_Two_Name", groupTwo.Key.Name);
|
||||
}
|
||||
|
|
@ -1051,12 +1051,12 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations
|
|||
// Assert
|
||||
var groupTwo = Assert.Single(enumNameAndGroup, e => e.Value.Equals("2", StringComparison.Ordinal));
|
||||
|
||||
using(new CultureReplacer("en-US", "en-US"))
|
||||
using (new CultureReplacer("en-US", "en-US"))
|
||||
{
|
||||
Assert.Equal("Loc_Two_Name en-US", groupTwo.Key.Name);
|
||||
}
|
||||
|
||||
using(new CultureReplacer("fr-FR", "fr-FR"))
|
||||
using (new CultureReplacer("fr-FR", "fr-FR"))
|
||||
{
|
||||
Assert.Equal("Loc_Two_Name fr-FR", groupTwo.Key.Name);
|
||||
}
|
||||
|
|
@ -1071,12 +1071,12 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations
|
|||
// Assert
|
||||
var groupThree = Assert.Single(enumNameAndGroup, e => e.Value.Equals("3", StringComparison.Ordinal));
|
||||
|
||||
using(new CultureReplacer("en-US", "en-US"))
|
||||
using (new CultureReplacer("en-US", "en-US"))
|
||||
{
|
||||
Assert.Equal("type three name en-US", groupThree.Key.Name);
|
||||
}
|
||||
|
||||
using(new CultureReplacer("fr-FR", "fr-FR"))
|
||||
using (new CultureReplacer("fr-FR", "fr-FR"))
|
||||
{
|
||||
Assert.Equal("type three name fr-FR", groupThree.Key.Name);
|
||||
}
|
||||
|
|
@ -1091,12 +1091,12 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations
|
|||
var groupThree = Assert.Single(enumNameAndGroup, e => e.Value.Equals("3", StringComparison.Ordinal));
|
||||
|
||||
// Assert
|
||||
using(new CultureReplacer("en-US", "en-US"))
|
||||
using (new CultureReplacer("en-US", "en-US"))
|
||||
{
|
||||
Assert.Equal("type three name en-US", groupThree.Key.Name);
|
||||
}
|
||||
|
||||
using(new CultureReplacer("fr-FR", "fr-FR"))
|
||||
using (new CultureReplacer("fr-FR", "fr-FR"))
|
||||
{
|
||||
Assert.Equal("type three name fr-FR", groupThree.Key.Name);
|
||||
}
|
||||
|
|
@ -1111,7 +1111,8 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations
|
|||
var required = new RequiredAttribute();
|
||||
|
||||
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));
|
||||
|
||||
// Act
|
||||
|
|
@ -1131,7 +1132,8 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations
|
|||
var provider = CreateProvider();
|
||||
|
||||
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));
|
||||
context.ValidationMetadata.IsRequired = initialValue;
|
||||
|
||||
|
|
@ -1152,8 +1154,9 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations
|
|||
typeof(NullableReferenceTypes),
|
||||
typeof(NullableReferenceTypes).GetProperty(nameof(NullableReferenceTypes.NonNullableReferenceType)));
|
||||
var key = ModelMetadataIdentity.ForProperty(
|
||||
typeof(NullableReferenceTypes),
|
||||
nameof(NullableReferenceTypes.NonNullableReferenceType), typeof(string));
|
||||
typeof(NullableReferenceTypes).GetProperty(nameof(NullableReferenceTypes.NonNullableReferenceType)),
|
||||
typeof(string),
|
||||
typeof(NullableReferenceTypes));
|
||||
var context = new ValidationMetadataProviderContext(key, attributes);
|
||||
|
||||
// Act
|
||||
|
|
@ -1174,9 +1177,11 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations
|
|||
var attributes = ModelAttributes.GetAttributesForProperty(
|
||||
typeof(NullableReferenceTypes),
|
||||
typeof(NullableReferenceTypes).GetProperty(nameof(NullableReferenceTypes.NonNullableReferenceTypeWithRequired)));
|
||||
|
||||
var key = ModelMetadataIdentity.ForProperty(
|
||||
typeof(NullableReferenceTypes),
|
||||
nameof(NullableReferenceTypes.NonNullableReferenceTypeWithRequired), typeof(string));
|
||||
typeof(NullableReferenceTypes).GetProperty(nameof(NullableReferenceTypes.NonNullableReferenceTypeWithRequired)),
|
||||
typeof(string),
|
||||
typeof(NullableReferenceTypes));
|
||||
var context = new ValidationMetadataProviderContext(key, attributes);
|
||||
|
||||
// Act
|
||||
|
|
@ -1201,9 +1206,12 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations
|
|||
var attributes = ModelAttributes.GetAttributesForProperty(
|
||||
typeof(NullableReferenceTypes),
|
||||
typeof(NullableReferenceTypes).GetProperty(nameof(NullableReferenceTypes.NonNullableReferenceType)));
|
||||
|
||||
var key = ModelMetadataIdentity.ForProperty(
|
||||
typeof(NullableReferenceTypes),
|
||||
nameof(NullableReferenceTypes.NonNullableReferenceType), typeof(string));
|
||||
typeof(NullableReferenceTypes).GetProperty(nameof(NullableReferenceTypes.NonNullableReferenceType)),
|
||||
typeof(string),
|
||||
typeof(NullableReferenceTypes));
|
||||
|
||||
var context = new ValidationMetadataProviderContext(key, attributes);
|
||||
|
||||
// Act
|
||||
|
|
@ -1214,6 +1222,189 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations
|
|||
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]
|
||||
public void CreateValidationMetadata_WillAddValidationAttributes_From_ValidationProviderAttribute()
|
||||
{
|
||||
|
|
@ -1227,7 +1418,8 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations
|
|||
});
|
||||
|
||||
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));
|
||||
|
||||
// Act
|
||||
|
|
@ -1254,7 +1446,8 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations
|
|||
var provider = CreateProvider();
|
||||
|
||||
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));
|
||||
context.BindingMetadata.IsBindingRequired = initialValue;
|
||||
|
||||
|
|
@ -1275,7 +1468,8 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations
|
|||
var provider = CreateProvider();
|
||||
|
||||
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));
|
||||
context.BindingMetadata.IsReadOnly = initialValue;
|
||||
|
||||
|
|
@ -1294,7 +1488,8 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations
|
|||
|
||||
var attribute = new TestValidationAttribute();
|
||||
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));
|
||||
|
||||
// Act
|
||||
|
|
@ -1313,7 +1508,29 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations
|
|||
|
||||
var attribute = new TestValidationAttribute();
|
||||
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));
|
||||
context.ValidationMetadata.ValidatorMetadata.Add(attribute);
|
||||
|
||||
|
|
@ -1479,7 +1696,7 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations
|
|||
|
||||
public bool Equals(KeyValuePair<EnumGroupAndName, string> x, KeyValuePair<EnumGroupAndName, string> y)
|
||||
{
|
||||
using(new CultureReplacer(string.Empty, string.Empty))
|
||||
using (new CultureReplacer(string.Empty, string.Empty))
|
||||
{
|
||||
return x.Key.Name.Equals(y.Key.Name, StringComparison.Ordinal)
|
||||
&& x.Key.Group.Equals(y.Key.Group, StringComparison.Ordinal);
|
||||
|
|
@ -1488,7 +1705,7 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations
|
|||
|
||||
public int GetHashCode(KeyValuePair<EnumGroupAndName, string> obj)
|
||||
{
|
||||
using(new CultureReplacer(string.Empty, string.Empty))
|
||||
using (new CultureReplacer(string.Empty, string.Empty))
|
||||
{
|
||||
return obj.Key.GetHashCode();
|
||||
}
|
||||
|
|
@ -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
|
||||
|
||||
public class TypeImplementIInterfaceWithNonNullProperty_AsNullable : AbstraceTypehNonNullProperty
|
||||
{
|
||||
public override string Property { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,8 +24,8 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations
|
|||
};
|
||||
|
||||
var key = ModelMetadataIdentity.ForProperty(
|
||||
typeof(ClassWithDataMemberIsRequiredTrue).GetProperty(nameof(ClassWithDataMemberIsRequiredTrue.StringProperty)),
|
||||
typeof(string),
|
||||
nameof(ClassWithDataMemberIsRequiredTrue.StringProperty),
|
||||
typeof(ClassWithDataMemberIsRequiredTrue));
|
||||
var context = new BindingMetadataProviderContext(key, GetModelAttributes(new object[0], attributes));
|
||||
|
||||
|
|
@ -50,8 +50,8 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations
|
|||
};
|
||||
|
||||
var key = ModelMetadataIdentity.ForProperty(
|
||||
typeof(ClassWithDataMemberIsRequiredFalse).GetProperty(nameof(ClassWithDataMemberIsRequiredFalse.StringProperty)),
|
||||
typeof(string),
|
||||
nameof(ClassWithDataMemberIsRequiredFalse.StringProperty),
|
||||
typeof(ClassWithDataMemberIsRequiredFalse));
|
||||
var context = new BindingMetadataProviderContext(key, GetModelAttributes(new object[0], attributes));
|
||||
|
||||
|
|
@ -98,8 +98,8 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations
|
|||
var provider = new DataMemberRequiredBindingMetadataProvider();
|
||||
|
||||
var key = ModelMetadataIdentity.ForProperty(
|
||||
typeof(ClassWithoutAttributes).GetProperty(nameof(ClassWithoutAttributes.StringProperty)),
|
||||
typeof(string),
|
||||
nameof(ClassWithoutAttributes.StringProperty),
|
||||
typeof(ClassWithoutAttributes));
|
||||
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(
|
||||
typeof(ClassWithDataMemberIsRequiredTrueWithoutDataContract).GetProperty(nameof(ClassWithDataMemberIsRequiredTrueWithoutDataContract.StringProperty)),
|
||||
typeof(string),
|
||||
nameof(ClassWithDataMemberIsRequiredTrueWithoutDataContract.StringProperty),
|
||||
typeof(ClassWithDataMemberIsRequiredTrueWithoutDataContract));
|
||||
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);
|
||||
exceptionDispatchInfo.Throw();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ using Microsoft.Extensions.Logging.Abstractions;
|
|||
using Microsoft.Extensions.ObjectPool;
|
||||
using Moq;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
using Xunit;
|
||||
|
||||
|
|
@ -21,8 +22,8 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
|||
{
|
||||
public class NewtonsoftJsonInputFormatterTest : JsonInputFormatterTestBase
|
||||
{
|
||||
private static readonly ObjectPoolProvider _objectPoolProvider = new DefaultObjectPoolProvider();
|
||||
private static readonly JsonSerializerSettings _serializerSettings = new JsonSerializerSettings();
|
||||
private readonly ObjectPoolProvider _objectPoolProvider = new DefaultObjectPoolProvider();
|
||||
private readonly JsonSerializerSettings _serializerSettings = new JsonSerializerSettings();
|
||||
|
||||
[Fact]
|
||||
public async Task Constructor_BuffersRequestBody_UsingDefaultOptions()
|
||||
|
|
@ -144,7 +145,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
|||
var serializerSettings = new JsonSerializerSettings();
|
||||
|
||||
// Act
|
||||
var formatter = new TestableJsonInputFormatter(serializerSettings);
|
||||
var formatter = new TestableJsonInputFormatter(serializerSettings, _objectPoolProvider);
|
||||
|
||||
// Assert
|
||||
Assert.Same(serializerSettings, formatter.SerializerSettings);
|
||||
|
|
@ -185,7 +186,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
|||
MaxDepth = 2,
|
||||
DateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind,
|
||||
};
|
||||
var formatter = new TestableJsonInputFormatter(settings);
|
||||
var formatter = new TestableJsonInputFormatter(settings, _objectPoolProvider);
|
||||
|
||||
// Act
|
||||
var actual = formatter.CreateJsonSerializer(null);
|
||||
|
|
@ -304,7 +305,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ReadAsync_lowInputFormatterExceptionMessages_DoesNotWrapJsonInputExceptions()
|
||||
public async Task ReadAsync_AllowInputFormatterExceptionMessages_DoesNotWrapJsonInputExceptions()
|
||||
{
|
||||
// Arrange
|
||||
var formatter = new NewtonsoftJsonInputFormatter(
|
||||
|
|
@ -336,10 +337,72 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
|||
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
|
||||
{
|
||||
public TestableJsonInputFormatter(JsonSerializerSettings settings)
|
||||
: base(GetLogger(), settings, ArrayPool<char>.Shared, _objectPoolProvider, new MvcOptions(), new MvcNewtonsoftJsonOptions())
|
||||
public TestableJsonInputFormatter(JsonSerializerSettings settings, ObjectPoolProvider objectPoolProvider)
|
||||
: base(GetLogger(), settings, ArrayPool<char>.Shared, objectPoolProvider, new MvcOptions(), new MvcNewtonsoftJsonOptions())
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -418,5 +481,26 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
|||
[JsonProperty(Required = Required.Always)]
|
||||
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);
|
||||
Assert.NotNull(property);
|
||||
|
||||
var key = ModelMetadataIdentity.ForProperty(property.PropertyType, propertyName, containerType);
|
||||
var key = ModelMetadataIdentity.ForProperty(property, property.PropertyType, containerType);
|
||||
|
||||
var builder = new MetadataBuilder(key);
|
||||
_detailsProvider.Builders.Add(builder);
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
</div>
|
||||
|
||||
<div class="main">
|
||||
<div class="top-row px-4">
|
||||
<div class="top-row px-4 auth">
|
||||
<LoginDisplay />
|
||||
<a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
{
|
||||
"DetailedErrors": true,
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft": "Warning",
|
||||
"Microsoft.Hosting.Lifetime": "Information"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,9 +9,9 @@ a, .btn-link {
|
|||
}
|
||||
|
||||
.btn-primary {
|
||||
color: #fff;
|
||||
background-color: #1b6ec2;
|
||||
border-color: #1861ac;
|
||||
color: #fff;
|
||||
background-color: #1b6ec2;
|
||||
border-color: #1861ac;
|
||||
}
|
||||
|
||||
app {
|
||||
|
|
@ -30,66 +30,72 @@ app {
|
|||
flex: 1;
|
||||
}
|
||||
|
||||
.main .top-row {
|
||||
background-color: #f7f7f7;
|
||||
border-bottom: 1px solid #d6d5d5;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
.main .top-row {
|
||||
background-color: #f7f7f7;
|
||||
border-bottom: 1px solid #d6d5d5;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.main .top-row > a {
|
||||
margin-left: 1.5rem;
|
||||
.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 {
|
||||
background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%);
|
||||
}
|
||||
|
||||
.sidebar .top-row {
|
||||
background-color: rgba(0,0,0,0.4);
|
||||
}
|
||||
.sidebar .top-row {
|
||||
background-color: rgba(0,0,0,0.4);
|
||||
}
|
||||
|
||||
.sidebar .navbar-brand {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
.sidebar .navbar-brand {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.sidebar .oi {
|
||||
width: 2rem;
|
||||
font-size: 1.1rem;
|
||||
vertical-align: text-top;
|
||||
top: -2px;
|
||||
}
|
||||
.sidebar .oi {
|
||||
width: 2rem;
|
||||
font-size: 1.1rem;
|
||||
vertical-align: text-top;
|
||||
top: -2px;
|
||||
}
|
||||
|
||||
.nav-item {
|
||||
font-size: 0.9rem;
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
.sidebar .nav-item {
|
||||
font-size: 0.9rem;
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.nav-item:first-of-type {
|
||||
padding-top: 1rem;
|
||||
}
|
||||
.sidebar .nav-item:first-of-type {
|
||||
padding-top: 1rem;
|
||||
}
|
||||
|
||||
.nav-item:last-of-type {
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
.sidebar .nav-item:last-of-type {
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
|
||||
.nav-item a {
|
||||
color: #d7d7d7;
|
||||
border-radius: 4px;
|
||||
height: 3rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
line-height: 3rem;
|
||||
}
|
||||
.sidebar .nav-item a {
|
||||
color: #d7d7d7;
|
||||
border-radius: 4px;
|
||||
height: 3rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
line-height: 3rem;
|
||||
}
|
||||
|
||||
.nav-item a.active {
|
||||
background-color: rgba(255,255,255,0.25);
|
||||
color: white;
|
||||
}
|
||||
.sidebar .nav-item a.active {
|
||||
background-color: rgba(255,255,255,0.25);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.nav-item a:hover {
|
||||
background-color: rgba(255,255,255,0.1);
|
||||
color: white;
|
||||
}
|
||||
.sidebar .nav-item a:hover {
|
||||
background-color: rgba(255,255,255,0.1);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.content {
|
||||
padding-top: 1.1rem;
|
||||
|
|
@ -131,9 +137,17 @@ app {
|
|||
}
|
||||
|
||||
@media (max-width: 767.98px) {
|
||||
.main .top-row {
|
||||
.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;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
|
|
|
|||
|
|
@ -10,10 +10,10 @@ namespace Microsoft.AspNetCore.Authentication.Facebook
|
|||
public static readonly string DisplayName = "Facebook";
|
||||
|
||||
// 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");
|
||||
Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode);
|
||||
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("client_id=", 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");
|
||||
Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode);
|
||||
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("client_id=", 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");
|
||||
Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode);
|
||||
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("client_id=", location);
|
||||
Assert.Contains("redirect_uri=", location);
|
||||
|
|
|
|||
|
|
@ -76,9 +76,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
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")]
|
||||
[ConditionalFact]
|
||||
[MinimumOSVersion(OperatingSystems.Windows, WindowsVersions.Win10_RS4)]
|
||||
public void ParseAddressUnixPipe()
|
||||
{
|
||||
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("http1AndHttp2", HttpProtocols.Http1AndHttp2)] // Gracefully falls back to HTTP/1
|
||||
[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)
|
||||
=> DefaultConfigSectionCanSetProtocols(input, expected);
|
||||
|
||||
|
|
@ -329,7 +329,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Tests
|
|||
[InlineData("http2", HttpProtocols.Http2)]
|
||||
[InlineData("http1AndHttp2", HttpProtocols.Http1AndHttp2)]
|
||||
[OSSkipCondition(OperatingSystems.MacOSX)]
|
||||
[OSSkipCondition(OperatingSystems.Windows, WindowsVersions.Win7)]
|
||||
[MinimumOSVersion(OperatingSystems.Windows, WindowsVersions.Win81)]
|
||||
public void DefaultConfigSectionCanSetProtocols_NonMacAndWin7(string input, HttpProtocols 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("http1AndHttp2", HttpProtocols.Http1AndHttp2)] // Gracefully falls back to HTTP/1
|
||||
[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) =>
|
||||
EndpointConfigSectionCanSetProtocols(input, expected);
|
||||
|
||||
|
|
@ -398,7 +398,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Tests
|
|||
[InlineData("http2", HttpProtocols.Http2)]
|
||||
[InlineData("http1AndHttp2", HttpProtocols.Http1AndHttp2)]
|
||||
[OSSkipCondition(OperatingSystems.MacOSX)]
|
||||
[OSSkipCondition(OperatingSystems.Windows, WindowsVersions.Win7)]
|
||||
[MinimumOSVersion(OperatingSystems.Windows, WindowsVersions.Win81)]
|
||||
public void EndpointConfigSectionCanSetProtocols_NonMacAndWin7(string input, HttpProtocols expected) =>
|
||||
EndpointConfigSectionCanSetProtocols(input, expected);
|
||||
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests.Http2
|
|||
|
||||
[ConditionalFact]
|
||||
[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.
|
||||
public void TlsAndHttp2NotSupportedOnWin7()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests.Http2
|
|||
|
||||
[CollectDump]
|
||||
[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)]
|
||||
public async Task GracefulShutdownWaitsForRequestsToFinish()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
|
|||
#if LIBUV
|
||||
[OSSkipCondition(OperatingSystems.Windows, SkipReason = "Libuv does not support unix domain sockets on Windows.")]
|
||||
#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
|
||||
[SkipOnHelix("https://github.com/aspnet/AspNetCore/issues/14382", Queues = "Windows.10.Amd64.Open")]
|
||||
[ConditionalFact]
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Xunit.Sdk;
|
||||
|
||||
namespace OpenQA.Selenium
|
||||
|
|
@ -13,15 +14,31 @@ namespace OpenQA.Selenium
|
|||
// case.
|
||||
public class BrowserAssertFailedException : XunitException
|
||||
{
|
||||
public BrowserAssertFailedException(IReadOnlyList<LogEntry> logs, Exception innerException, string screenShotPath)
|
||||
: base(BuildMessage(innerException, logs, screenShotPath), innerException)
|
||||
public BrowserAssertFailedException(IReadOnlyList<LogEntry> logs, Exception innerException, string screenShotPath, string innerHTML)
|
||||
: base(BuildMessage(innerException, logs, screenShotPath, innerHTML), innerException)
|
||||
{
|
||||
}
|
||||
|
||||
private static string BuildMessage(Exception innerException, IReadOnlyList<LogEntry> logs, string screenShotPath) =>
|
||||
innerException.ToString() + Environment.NewLine +
|
||||
(File.Exists(screenShotPath) ? $"Screen shot captured at '{screenShotPath}'" + Environment.NewLine : "") +
|
||||
(logs.Count > 0 ? "Encountered browser logs" : "No browser logs found") + " while running the assertion." + Environment.NewLine +
|
||||
string.Join(Environment.NewLine, logs);
|
||||
private static string BuildMessage(Exception exception, IReadOnlyList<LogEntry> logs, string screenShotPath, string innerHTML)
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
builder.AppendLine(exception.ToString());
|
||||
|
||||
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