forked from aspnet/Mvc
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
71a815b
commit 8c4bcf1
Showing
25 changed files
with
486 additions
and
131 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
45 changes: 45 additions & 0 deletions
45
src/Microsoft.AspNetCore.Mvc.Abstractions/ModelBinding/Validation/ValidatorItem.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,45 @@ | ||
// Copyright (c) .NET Foundation. All rights reserved. | ||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. | ||
|
||
namespace Microsoft.AspNetCore.Mvc.ModelBinding.Validation | ||
{ | ||
/// <summary> | ||
/// Used to associate validators with <see cref="ValidatorMetadata"/> instances | ||
/// as part of <see cref="ModelValidatorProviderContext"/>. An <see cref="IModelValidator"/> should | ||
/// inspect <see cref="ModelValidatorProviderContext.Results"/> and set <see cref="Validator"/> and | ||
/// <see cref="IsReusable"/> as appropriate. | ||
/// </summary> | ||
public class ValidatorItem | ||
{ | ||
/// <summary> | ||
/// Creates a new <see cref="ValidatorItem"/>. | ||
/// </summary> | ||
public ValidatorItem() | ||
{ | ||
} | ||
|
||
/// <summary> | ||
/// Creates a new <see cref="ValidatorItem"/>. | ||
/// </summary> | ||
/// <param name="validatorMetadata">The <see cref="ValidatorMetadata"/>.</param> | ||
public ValidatorItem(object validatorMetadata) | ||
{ | ||
ValidatorMetadata = validatorMetadata; | ||
} | ||
|
||
/// <summary> | ||
/// Gets the metadata associated with the <see cref="Validator"/>. | ||
/// </summary> | ||
public object ValidatorMetadata { get; } | ||
|
||
/// <summary> | ||
/// Gets or sets the <see cref="IModelValidator"/>. | ||
/// </summary> | ||
public IModelValidator Validator { get; set; } | ||
|
||
/// <summary> | ||
/// Gets or sets a value indicating whether or not <see cref="Validator"/> can be reused across requests. | ||
/// </summary> | ||
public bool IsReusable { get; set; } | ||
} | ||
} |
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
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
145 changes: 145 additions & 0 deletions
145
src/Microsoft.AspNetCore.Mvc.Core/Internal/ValidatorCache.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,145 @@ | ||
// 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.Concurrent; | ||
using System.Collections.Generic; | ||
using System.Diagnostics; | ||
using Microsoft.AspNetCore.Mvc.ModelBinding; | ||
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation; | ||
|
||
namespace Microsoft.AspNetCore.Mvc.Internal | ||
{ | ||
public class ValidatorCache | ||
{ | ||
private readonly IReadOnlyList<IModelValidator> EmptyArray = new IModelValidator[0]; | ||
|
||
private readonly ConcurrentDictionary<ModelMetadata, CacheEntry> _cacheEntries = new ConcurrentDictionary<ModelMetadata, CacheEntry>(); | ||
|
||
public IReadOnlyList<IModelValidator> GetValidators(ModelMetadata metadata, IModelValidatorProvider validatorProvider) | ||
{ | ||
CacheEntry entry; | ||
if (_cacheEntries.TryGetValue(metadata, out entry)) | ||
{ | ||
return GetValidatorsFromEntry(entry, metadata, validatorProvider); | ||
} | ||
|
||
var items = new List<ValidatorItem>(metadata.ValidatorMetadata.Count); | ||
for (var i = 0; i < metadata.ValidatorMetadata.Count; i++) | ||
{ | ||
items.Add(new ValidatorItem(metadata.ValidatorMetadata[i])); | ||
} | ||
|
||
ExecuteProvider(validatorProvider, metadata, items); | ||
|
||
var validators = ExtractValidators(items); | ||
|
||
var allValidatorsCached = true; | ||
for (var i = 0; i < items.Count; i++) | ||
{ | ||
var item = items[i]; | ||
if (!item.IsReusable) | ||
{ | ||
item.Validator = null; | ||
allValidatorsCached = false; | ||
} | ||
} | ||
|
||
if (allValidatorsCached) | ||
{ | ||
entry = new CacheEntry(validators); | ||
} | ||
else | ||
{ | ||
entry = new CacheEntry(items); | ||
} | ||
|
||
_cacheEntries.TryAdd(metadata, entry); | ||
|
||
return validators; | ||
} | ||
|
||
private IReadOnlyList<IModelValidator> GetValidatorsFromEntry(CacheEntry entry, ModelMetadata metadata, IModelValidatorProvider validationProvider) | ||
{ | ||
Debug.Assert(entry.Validators != null || entry.Items != null); | ||
|
||
if (entry.Validators != null) | ||
{ | ||
return entry.Validators; | ||
} | ||
|
||
var items = new List<ValidatorItem>(entry.Items.Count); | ||
for (var i = 0; i < entry.Items.Count; i++) | ||
{ | ||
var item = entry.Items[i]; | ||
if (item.IsReusable) | ||
{ | ||
items.Add(item); | ||
} | ||
else | ||
{ | ||
items.Add(new ValidatorItem(item.ValidatorMetadata)); | ||
} | ||
} | ||
|
||
ExecuteProvider(validationProvider, metadata, items); | ||
|
||
return ExtractValidators(items); | ||
} | ||
|
||
private void ExecuteProvider(IModelValidatorProvider validatorProvider, ModelMetadata metadata, List<ValidatorItem> items) | ||
{ | ||
var context = new ModelValidatorProviderContext(metadata, items); | ||
validatorProvider.GetValidators(context); | ||
} | ||
|
||
private IReadOnlyList<IModelValidator> ExtractValidators(List<ValidatorItem> items) | ||
{ | ||
var count = 0; | ||
for (var i = 0; i < items.Count; i++) | ||
{ | ||
if (items[i].Validator != null) | ||
{ | ||
count++; | ||
} | ||
} | ||
|
||
if (count == 0) | ||
{ | ||
return EmptyArray; | ||
} | ||
|
||
var validators = new IModelValidator[count]; | ||
|
||
var validatorIndex = 0; | ||
for (int i = 0; i < items.Count; i++) | ||
{ | ||
var validator = items[i].Validator; | ||
if (validator != null) | ||
{ | ||
validators[validatorIndex++] = validator; | ||
} | ||
} | ||
|
||
return validators; | ||
} | ||
|
||
private struct CacheEntry | ||
{ | ||
public CacheEntry(IReadOnlyList<IModelValidator> validators) | ||
{ | ||
Validators = validators; | ||
Items = null; | ||
} | ||
|
||
public CacheEntry(List<ValidatorItem> items) | ||
{ | ||
Items = items; | ||
Validators = null; | ||
} | ||
|
||
public IReadOnlyList<IModelValidator> Validators { get; } | ||
|
||
public List<ValidatorItem> Items { get; } | ||
} | ||
} | ||
} |
Oops, something went wrong.