More read interface IList.Count once rather than per iteration + miscellany (#11253)
* Read interface IList.Count once rather than per iteration Inspired by #9962, read .Count once rather than once per loop iteration. * Use nameof() instead of ToString() Use constant nameof() on enum value, rather than runtime ToString(). * Right-size dictionary Initialize dictionary with a fixed number of elements to the number of elements it contains. * Use DisposeAsync() Use DisposeAsync() on FileBufferingReadStream in input formatters. * Override DisposeAsync() Override DisposeAsync() to call DisposeAsync() on the inner stream. * Use GetValueOrDefault() for content-length Use GetValueOrDefault() to read the content length once instead of checking HasValue once and Value up to three times. * Update Microsoft.AspNetCore.WebUtilities.netcoreapp3.0.cs Add DisposeAsync(). * Use DisposeAsync() Use DisposeAsync() on transcoding streams as other formatters do.
This commit is contained in:
parent
4f67ff9216
commit
cc96e988f4
|
|
@ -54,6 +54,8 @@ namespace Microsoft.AspNetCore.WebUtilities
|
|||
public override long Position { get { throw null; } set { } }
|
||||
public string TempFileName { get { throw null; } }
|
||||
protected override void Dispose(bool disposing) { }
|
||||
[System.Diagnostics.DebuggerStepThroughAttribute]
|
||||
public override System.Threading.Tasks.ValueTask DisposeAsync() { throw null; }
|
||||
public override void Flush() { }
|
||||
public override int Read(byte[] buffer, int offset, int count) { throw null; }
|
||||
[System.Diagnostics.DebuggerStepThroughAttribute]
|
||||
|
|
|
|||
|
|
@ -366,6 +366,20 @@ namespace Microsoft.AspNetCore.WebUtilities
|
|||
}
|
||||
}
|
||||
|
||||
public async override ValueTask DisposeAsync()
|
||||
{
|
||||
if (!_disposed)
|
||||
{
|
||||
_disposed = true;
|
||||
if (_rentedBuffer != null)
|
||||
{
|
||||
_bytePool.Return(_rentedBuffer);
|
||||
}
|
||||
|
||||
await _buffer.DisposeAsync();
|
||||
}
|
||||
}
|
||||
|
||||
private void ThrowIfDisposed()
|
||||
{
|
||||
if (_disposed)
|
||||
|
|
|
|||
|
|
@ -569,9 +569,11 @@ namespace Microsoft.AspNetCore.Mvc.ApiExplorer
|
|||
newContainerName = GetName(containerName, bindingContext);
|
||||
}
|
||||
|
||||
for (var i = 0; i < modelMetadata.Properties.Count; i++)
|
||||
var metadataProperties = modelMetadata.Properties;
|
||||
var metadataPropertiesCount = metadataProperties.Count;
|
||||
for (var i = 0; i < metadataPropertiesCount; i++)
|
||||
{
|
||||
var propertyMetadata = modelMetadata.Properties[i];
|
||||
var propertyMetadata = metadataProperties[i];
|
||||
var key = new PropertyKey(propertyMetadata, source);
|
||||
var bindingInfo = BindingInfo.GetBindingInfo(Enumerable.Empty<object>(), propertyMetadata);
|
||||
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
|||
{
|
||||
if (inputStream is TranscodingReadStream transcoding)
|
||||
{
|
||||
transcoding.Dispose();
|
||||
await transcoding.DisposeAsync();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
|||
{
|
||||
if (writeStream is TranscodingWriteStream transcoding)
|
||||
{
|
||||
transcoding.Dispose();
|
||||
await transcoding.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -97,15 +97,22 @@ namespace Microsoft.AspNetCore.Mvc.Cors
|
|||
|
||||
private static void ConfigureCorsActionConstraint(ActionModel actionModel)
|
||||
{
|
||||
for (var i = 0; i < actionModel.Selectors.Count; i++)
|
||||
{
|
||||
var selectorModel = actionModel.Selectors[i];
|
||||
var selectors = actionModel.Selectors;
|
||||
// Read interface .Count once rather than per iteration
|
||||
var selectorsCount = selectors.Count;
|
||||
|
||||
for (var j = 0; j < selectorModel.ActionConstraints.Count; j++)
|
||||
for (var i = 0; i < selectorsCount; i++)
|
||||
{
|
||||
var selectorModel = selectors[i];
|
||||
|
||||
var actionConstraints = selectorModel.ActionConstraints;
|
||||
// Read interface .Count once rather than per iteration
|
||||
var actionConstraintsCount = actionConstraints.Count;
|
||||
for (var j = 0; j < actionConstraintsCount; j++)
|
||||
{
|
||||
if (selectorModel.ActionConstraints[j] is HttpMethodActionConstraint httpConstraint)
|
||||
if (actionConstraints[j] is HttpMethodActionConstraint httpConstraint)
|
||||
{
|
||||
selectorModel.ActionConstraints[j] = new CorsHttpMethodActionConstraint(httpConstraint);
|
||||
actionConstraints[j] = new CorsHttpMethodActionConstraint(httpConstraint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -131,11 +138,14 @@ namespace Microsoft.AspNetCore.Mvc.Cors
|
|||
|
||||
foreach (var selector in action.Selectors)
|
||||
{
|
||||
for (var i = 0; i < selector.EndpointMetadata.Count; i++)
|
||||
var metadata = selector.EndpointMetadata;
|
||||
// Read interface .Count once rather than per iteration
|
||||
var metadataCount = metadata.Count;
|
||||
for (var i = 0; i < metadataCount; i++)
|
||||
{
|
||||
if (selector.EndpointMetadata[i] is HttpMethodMetadata httpMethodMetadata)
|
||||
if (metadata[i] is HttpMethodMetadata httpMethodMetadata)
|
||||
{
|
||||
selector.EndpointMetadata[i] = new HttpMethodMetadata(httpMethodMetadata.HttpMethods, acceptCorsPreflight: true);
|
||||
metadata[i] = new HttpMethodMetadata(httpMethodMetadata.HttpMethods, acceptCorsPreflight: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,7 +39,9 @@ namespace Microsoft.AspNetCore.Mvc.Cors
|
|||
request.Headers.TryGetValue(AccessControlRequestMethod, out var accessControlRequestMethod) &&
|
||||
!StringValues.IsNullOrEmpty(accessControlRequestMethod))
|
||||
{
|
||||
for (var i = 0; i < methods.Count; i++)
|
||||
// Read interface .Count once rather than per iteration
|
||||
var methodsCount = methods.Count;
|
||||
for (var i = 0; i < methodsCount; i++)
|
||||
{
|
||||
var supportedMethod = methods[i];
|
||||
if (string.Equals(supportedMethod, accessControlRequestMethod, StringComparison.OrdinalIgnoreCase))
|
||||
|
|
|
|||
|
|
@ -67,9 +67,12 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations
|
|||
|
||||
var hasRequiredAttribute = false;
|
||||
|
||||
for (var i = 0; i < context.Results.Count; i++)
|
||||
var results = context.Results;
|
||||
// Read interface .Count once rather than per iteration
|
||||
var resultsCount = results.Count;
|
||||
for (var i = 0; i < resultsCount; i++)
|
||||
{
|
||||
var validatorItem = context.Results[i];
|
||||
var validatorItem = results[i];
|
||||
if (validatorItem.Validator != null)
|
||||
{
|
||||
// Check if a required attribute is already cached.
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations
|
|||
}
|
||||
else if (displayFormatAttribute != null && !displayFormatAttribute.HtmlEncode)
|
||||
{
|
||||
displayMetadata.DataTypeName = DataType.Html.ToString();
|
||||
displayMetadata.DataTypeName = nameof(DataType.Html);
|
||||
}
|
||||
|
||||
var containerType = context.Key.ContainerType ?? context.Key.ModelType;
|
||||
|
|
@ -322,11 +322,14 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations
|
|||
throw new ArgumentNullException(nameof(context));
|
||||
}
|
||||
|
||||
var attributes = new List<object>(context.Attributes.Count);
|
||||
|
||||
for (var i = 0; i < context.Attributes.Count; i++)
|
||||
// Read interface .Count once rather than per iteration
|
||||
var contextAttributes = context.Attributes;
|
||||
var contextAttributesCount = contextAttributes.Count;
|
||||
var attributes = new List<object>(contextAttributesCount);
|
||||
|
||||
for (var i = 0; i < contextAttributesCount; i++)
|
||||
{
|
||||
var attribute = context.Attributes[i];
|
||||
var attribute = contextAttributes[i];
|
||||
if (attribute is ValidationProviderAttribute validationProviderAttribute)
|
||||
{
|
||||
attributes.AddRange(validationProviderAttribute.GetValidationAttributes());
|
||||
|
|
|
|||
|
|
@ -59,9 +59,12 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations
|
|||
_stringLocalizerFactory);
|
||||
}
|
||||
|
||||
for (var i = 0; i < context.Results.Count; i++)
|
||||
var results = context.Results;
|
||||
// Read interface .Count once rather than per iteration
|
||||
var resultsCount = results.Count;
|
||||
for (var i = 0; i < resultsCount; i++)
|
||||
{
|
||||
var validatorItem = context.Results[i];
|
||||
var validatorItem = results[i];
|
||||
if (validatorItem.Validator != null)
|
||||
{
|
||||
continue;
|
||||
|
|
@ -106,7 +109,9 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations
|
|||
return true;
|
||||
}
|
||||
|
||||
for (var i = 0; i < validatorMetadata.Count; i++)
|
||||
// Read interface .Count once rather than per iteration
|
||||
var validatorMetadataCount = validatorMetadata.Count;
|
||||
for (var i = 0; i < validatorMetadataCount; i++)
|
||||
{
|
||||
if (validatorMetadata[i] is ValidationAttribute)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -24,9 +24,11 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations
|
|||
}
|
||||
|
||||
// Perf: Avoid allocations
|
||||
for (var i = 0; i < context.Results.Count; i++)
|
||||
var results = context.Results;
|
||||
var resultsCount = results.Count;
|
||||
for (var i = 0; i < resultsCount; i++)
|
||||
{
|
||||
var validatorItem = context.Results[i];
|
||||
var validatorItem = results[i];
|
||||
// Don't overwrite anything that was done by a previous provider.
|
||||
if (validatorItem.Validator != null)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -27,9 +27,12 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations
|
|||
typeToValidate == typeof(double) ||
|
||||
typeToValidate == typeof(decimal))
|
||||
{
|
||||
for (var i = 0; i < context.Results.Count; i++)
|
||||
var results = context.Results;
|
||||
// Read interface .Count once rather than per iteration
|
||||
var resultsCount = results.Count;
|
||||
for (var i = 0; i < resultsCount; i++)
|
||||
{
|
||||
var validator = context.Results[i].Validator;
|
||||
var validator = results[i].Validator;
|
||||
if (validator != null && validator is NumericClientModelValidator)
|
||||
{
|
||||
// A validator is already present. No need to add one.
|
||||
|
|
@ -37,7 +40,7 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations
|
|||
}
|
||||
}
|
||||
|
||||
context.Results.Add(new ClientValidatorItem
|
||||
results.Add(new ClientValidatorItem
|
||||
{
|
||||
Validator = new NumericClientModelValidator(),
|
||||
IsReusable = true
|
||||
|
|
|
|||
|
|
@ -124,10 +124,11 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
|||
// XmlDataContractSerializer does synchronous reads. In order to avoid blocking on the stream, we asynchronously
|
||||
// read everything into a buffer, and then seek back to the beginning.
|
||||
var memoryThreshold = DefaultMemoryThreshold;
|
||||
if (request.ContentLength.HasValue && request.ContentLength.Value > 0 && request.ContentLength.Value < memoryThreshold)
|
||||
var contentLength = request.ContentLength.GetValueOrDefault();
|
||||
if (contentLength > 0 && contentLength < memoryThreshold)
|
||||
{
|
||||
// If the Content-Length is known and is smaller than the default buffer size, use it.
|
||||
memoryThreshold = (int)request.ContentLength.Value;
|
||||
memoryThreshold = (int)contentLength;
|
||||
}
|
||||
|
||||
readStream = new FileBufferingReadStream(request.Body, memoryThreshold);
|
||||
|
|
@ -163,7 +164,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
|||
{
|
||||
if (readStream is FileBufferingReadStream fileBufferingReadStream)
|
||||
{
|
||||
fileBufferingReadStream.Dispose();
|
||||
await fileBufferingReadStream.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -104,10 +104,11 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
|||
// XmlSerializer does synchronous reads. In order to avoid blocking on the stream, we asynchronously
|
||||
// read everything into a buffer, and then seek back to the beginning.
|
||||
var memoryThreshold = DefaultMemoryThreshold;
|
||||
if (request.ContentLength.HasValue && request.ContentLength.Value > 0 && request.ContentLength.Value < memoryThreshold)
|
||||
var contentLength = request.ContentLength.GetValueOrDefault();
|
||||
if (contentLength > 0 && contentLength < memoryThreshold)
|
||||
{
|
||||
// If the Content-Length is known and is smaller than the default buffer size, use it.
|
||||
memoryThreshold = (int)request.ContentLength.Value;
|
||||
memoryThreshold = (int)contentLength;
|
||||
}
|
||||
|
||||
readStream = new FileBufferingReadStream(request.Body, memoryThreshold);
|
||||
|
|
@ -156,7 +157,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
|||
{
|
||||
if (readStream is FileBufferingReadStream fileBufferingReadStream)
|
||||
{
|
||||
fileBufferingReadStream.Dispose();
|
||||
await fileBufferingReadStream.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ namespace Microsoft.AspNetCore.Mvc.NewtonsoftJson
|
|||
private static readonly ConcurrentDictionary<Type, Func<JObject, object>> _dictionaryConverters =
|
||||
new ConcurrentDictionary<Type, Func<JObject, object>>();
|
||||
|
||||
private static readonly Dictionary<JTokenType, Type> _tokenTypeLookup = new Dictionary<JTokenType, Type>
|
||||
private static readonly Dictionary<JTokenType, Type> _tokenTypeLookup = new Dictionary<JTokenType, Type>(8)
|
||||
{
|
||||
{ JTokenType.String, typeof(string) },
|
||||
{ JTokenType.Integer, typeof(int) },
|
||||
|
|
|
|||
|
|
@ -134,10 +134,11 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
|||
// JSON.Net does synchronous reads. In order to avoid blocking on the stream, we asynchronously
|
||||
// read everything into a buffer, and then seek back to the beginning.
|
||||
var memoryThreshold = DefaultMemoryThreshold;
|
||||
if (request.ContentLength.HasValue && request.ContentLength.Value > 0 && request.ContentLength.Value < memoryThreshold)
|
||||
var contentLength = request.ContentLength.GetValueOrDefault();
|
||||
if (contentLength > 0 && contentLength < memoryThreshold)
|
||||
{
|
||||
// If the Content-Length is known and is smaller than the default buffer size, use it.
|
||||
memoryThreshold = (int)request.ContentLength.Value;
|
||||
memoryThreshold = (int)contentLength;
|
||||
}
|
||||
|
||||
readStream = new FileBufferingReadStream(request.Body, memoryThreshold);
|
||||
|
|
@ -171,7 +172,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
|||
|
||||
if (readStream is FileBufferingReadStream fileBufferingReadStream)
|
||||
{
|
||||
fileBufferingReadStream.Dispose();
|
||||
await fileBufferingReadStream.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue