This repository has been archived by the owner on Dec 14, 2018. It is now read-only.
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Shortcircuit validation when using default validator providers and no…
… validation metadata is discovered Fixes #5887
- Loading branch information
Showing
35 changed files
with
1,992 additions
and
39 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
75 changes: 75 additions & 0 deletions
75
benchmarks/Microsoft.AspNetCore.Mvc.Performance/ValidationVisitorBenchmarkBase.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
// 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 BenchmarkDotNet.Attributes; | ||
using Microsoft.AspNetCore.Http; | ||
using Microsoft.AspNetCore.Mvc.Abstractions; | ||
using Microsoft.AspNetCore.Mvc.DataAnnotations; | ||
using Microsoft.AspNetCore.Mvc.Internal; | ||
using Microsoft.AspNetCore.Mvc.ModelBinding; | ||
using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata; | ||
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation; | ||
using Microsoft.AspNetCore.Routing; | ||
using Microsoft.Extensions.Options; | ||
|
||
namespace Microsoft.AspNetCore.Mvc.Performance | ||
{ | ||
public abstract class ValidationVisitorBenchmarkBase | ||
{ | ||
protected const int Iterations = 4; | ||
|
||
protected static readonly IModelValidatorProvider[] ValidatorProviders = new IModelValidatorProvider[] | ||
{ | ||
new DefaultModelValidatorProvider(), | ||
new DataAnnotationsModelValidatorProvider( | ||
new ValidationAttributeAdapterProvider(), | ||
Options.Create(new MvcDataAnnotationsLocalizationOptions()), | ||
null), | ||
}; | ||
|
||
protected static readonly CompositeModelValidatorProvider CompositeModelValidatorProvider = new CompositeModelValidatorProvider(ValidatorProviders); | ||
|
||
public abstract object Model { get; } | ||
|
||
public ModelMetadataProvider BaselineModelMetadataProvider { get; private set; } | ||
public ModelMetadataProvider ModelMetadataProvider { get; private set; } | ||
public ModelMetadata BaselineModelMetadata { get; private set; } | ||
public ModelMetadata ModelMetadata { get; private set; } | ||
public ActionContext ActionContext { get; private set; } | ||
public ValidatorCache ValidatorCache { get; private set; } | ||
|
||
[GlobalSetup] | ||
public void Setup() | ||
{ | ||
BaselineModelMetadataProvider = CreateModelMetadataProvider(addHasValidatorsProvider: false); | ||
ModelMetadataProvider = CreateModelMetadataProvider(addHasValidatorsProvider: true); | ||
|
||
BaselineModelMetadata = BaselineModelMetadataProvider.GetMetadataForType(Model.GetType()); | ||
ModelMetadata = ModelMetadataProvider.GetMetadataForType(Model.GetType()); | ||
ActionContext = GetActionContext(); | ||
ValidatorCache = new ValidatorCache(); | ||
} | ||
|
||
protected static ModelMetadataProvider CreateModelMetadataProvider(bool addHasValidatorsProvider) | ||
{ | ||
var detailsProviders = new List<IMetadataDetailsProvider> | ||
{ | ||
new DefaultValidationMetadataProvider(), | ||
}; | ||
|
||
if (addHasValidatorsProvider) | ||
{ | ||
detailsProviders.Add(new HasValidatorsValidationMetadataProvider(ValidatorProviders)); | ||
} | ||
|
||
var compositeDetailsProvider = new DefaultCompositeMetadataDetailsProvider(detailsProviders); | ||
return new DefaultModelMetadataProvider(compositeDetailsProvider, Options.Create(new MvcOptions())); | ||
} | ||
|
||
protected static ActionContext GetActionContext() | ||
{ | ||
return new ActionContext(new DefaultHttpContext(), new RouteData(), new ActionDescriptor()); | ||
} | ||
} | ||
} |
42 changes: 42 additions & 0 deletions
42
benchmarks/Microsoft.AspNetCore.Mvc.Performance/ValidationVisitorByteArrayBenchmark.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
// 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 BenchmarkDotNet.Attributes; | ||
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation; | ||
|
||
namespace Microsoft.AspNetCore.Mvc.Performance | ||
{ | ||
public class ValidationVisitorByteArrayBenchmark : ValidationVisitorBenchmarkBase | ||
{ | ||
public override object Model { get; } = new byte[30]; | ||
|
||
[Benchmark(Baseline = true, Description = "validation for byte arrays baseline", OperationsPerInvoke = Iterations)] | ||
public void Baseline() | ||
{ | ||
// Baseline for validating a byte array of size 30, without the ModelMetadata.HasValidators optimization. | ||
// This is the behavior as of 2.1. | ||
var validationVisitor = new ValidationVisitor( | ||
ActionContext, | ||
CompositeModelValidatorProvider, | ||
ValidatorCache, | ||
BaselineModelMetadataProvider, | ||
new ValidationStateDictionary()); | ||
|
||
validationVisitor.Validate(BaselineModelMetadata, "key", Model); | ||
} | ||
|
||
[Benchmark(Description = "validation for byte arrays", OperationsPerInvoke = Iterations)] | ||
public void HasValidators() | ||
{ | ||
// Validating a byte array of size 30, with the ModelMetadata.HasValidators optimization. | ||
var validationVisitor = new ValidationVisitor( | ||
ActionContext, | ||
CompositeModelValidatorProvider, | ||
ValidatorCache, | ||
ModelMetadataProvider, | ||
new ValidationStateDictionary()); | ||
|
||
validationVisitor.Validate(ModelMetadata, "key", Model); | ||
} | ||
} | ||
} |
92 changes: 92 additions & 0 deletions
92
...rks/Microsoft.AspNetCore.Mvc.Performance/ValidationVisitorModelWithValidatedProperties.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
// 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 BenchmarkDotNet.Attributes; | ||
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation; | ||
|
||
namespace Microsoft.AspNetCore.Mvc.Performance | ||
{ | ||
public class ValidationVisitorModelWithValidatedProperties : ValidationVisitorBenchmarkBase | ||
{ | ||
public class Person | ||
{ | ||
[Required] | ||
public int Id { get; set; } | ||
|
||
[Required] | ||
[StringLength(20)] | ||
public string Name { get; set; } | ||
|
||
public string Description { get; set; } | ||
|
||
public IList<Address> Address { get; set; } | ||
} | ||
|
||
public class Address | ||
{ | ||
[Required] | ||
public string Street { get; set; } | ||
|
||
public string Street2 { get; set; } | ||
|
||
public string Type { get; set; } | ||
|
||
[Required] | ||
public string Zip { get; set; } | ||
} | ||
|
||
public override object Model { get; } = new Person | ||
{ | ||
Id = 10, | ||
Name = "Test", | ||
Address = new List<Address> | ||
{ | ||
new Address | ||
{ | ||
Street = "1 Microsoft Way", | ||
Type = "Work", | ||
Zip = "98056", | ||
}, | ||
new Address | ||
{ | ||
Street = "15701 NE 39th St", | ||
Type = "Home", | ||
Zip = "98052", | ||
} | ||
}, | ||
}; | ||
|
||
[Benchmark(Baseline = true, Description = "validation for a model with some validated properties - baseline", OperationsPerInvoke = Iterations)] | ||
public void Visit_TypeWithSomeValidatedProperties_Baseline() | ||
{ | ||
// Baseline for validating a typical model with some properties that require validation. | ||
// This executes without the ModelMetadata.HasValidators optimization. | ||
|
||
var validationVisitor = new ValidationVisitor( | ||
ActionContext, | ||
CompositeModelValidatorProvider, | ||
ValidatorCache, | ||
BaselineModelMetadataProvider, | ||
new ValidationStateDictionary()); | ||
|
||
validationVisitor.Validate(BaselineModelMetadata, "key", Model); | ||
} | ||
|
||
[Benchmark(Description = "validation for a model with some validated properties", OperationsPerInvoke = Iterations)] | ||
public void Visit_TypeWithSomeValidatedProperties() | ||
{ | ||
// Validating a typical model with some properties that require validation. | ||
// This executes with the ModelMetadata.HasValidators optimization. | ||
var validationVisitor = new ValidationVisitor( | ||
ActionContext, | ||
CompositeModelValidatorProvider, | ||
ValidatorCache, | ||
ModelMetadataProvider, | ||
new ValidationStateDictionary()); | ||
|
||
validationVisitor.Validate(ModelMetadata, "key", Model); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.