From 0989231ed58706676e7780071dfd5a1c76c51eea Mon Sep 17 00:00:00 2001 From: Pranav K Date: Thu, 2 Aug 2018 15:09:48 -0700 Subject: [PATCH 1/2] Make structs readonly --- .../ActionSelectorCandidate.cs | 2 +- .../ModelBinding/EnumGroupAndName.cs | 2 +- .../Metadata/ModelMetadataIdentity.cs | 41 +++++++++---------- .../ModelBinding/ModelBindingContext.cs | 2 +- .../ModelBinding/ModelBindingResult.cs | 2 +- .../ModelBinding/ModelStateDictionary.cs | 6 +-- .../ModelBinding/ValueProviderResult.cs | 2 +- ...ApiActionsAreAttributeRoutedFixProvider.cs | 2 +- .../DefaultApiDescriptionProvider.cs | 2 +- .../Formatters/MediaType.cs | 4 +- .../Internal/ClientValidatorCache.cs | 2 +- .../ControllerBinderDelegateProvider.cs | 2 +- .../Internal/FilterCursorItem.cs | 2 +- .../Internal/FilterFactoryResult.cs | 2 +- .../Internal/MediaTypeSegmentWithQuality.cs | 2 +- .../Internal/ValidatorCache.cs | 2 +- .../Metadata/DefaultModelMetadataProvider.cs | 2 +- .../ModelBinding/ModelBinderFactory.cs | 2 +- .../Validation/ValidationVisitor.cs | 2 +- .../Internal/ViewLocationCacheItem.cs | 2 +- .../Internal/ViewLocationCacheKey.cs | 2 +- .../RazorPageFactoryResult.cs | 2 +- .../RazorPageResult.cs | 2 +- .../Internal/PageBinderFactory.cs | 2 +- .../Internal/GlobbingUrlBuilder.cs | 2 +- .../Internal/ViewBufferValue.cs | 8 ++-- .../ViewFeatures/MemberExpressionCacheKey.cs | 6 +-- 27 files changed, 53 insertions(+), 56 deletions(-) diff --git a/src/Microsoft.AspNetCore.Mvc.Abstractions/ActionConstraints/ActionSelectorCandidate.cs b/src/Microsoft.AspNetCore.Mvc.Abstractions/ActionConstraints/ActionSelectorCandidate.cs index c2251cd371..7cf58a4845 100644 --- a/src/Microsoft.AspNetCore.Mvc.Abstractions/ActionConstraints/ActionSelectorCandidate.cs +++ b/src/Microsoft.AspNetCore.Mvc.Abstractions/ActionConstraints/ActionSelectorCandidate.cs @@ -10,7 +10,7 @@ namespace Microsoft.AspNetCore.Mvc.ActionConstraints /// /// A candidate action for action selection. /// - public struct ActionSelectorCandidate + public readonly struct ActionSelectorCandidate { /// /// Creates a new . diff --git a/src/Microsoft.AspNetCore.Mvc.Abstractions/ModelBinding/EnumGroupAndName.cs b/src/Microsoft.AspNetCore.Mvc.Abstractions/ModelBinding/EnumGroupAndName.cs index 0ad0117e5d..d4a141ed00 100644 --- a/src/Microsoft.AspNetCore.Mvc.Abstractions/ModelBinding/EnumGroupAndName.cs +++ b/src/Microsoft.AspNetCore.Mvc.Abstractions/ModelBinding/EnumGroupAndName.cs @@ -8,7 +8,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding /// /// An abstraction used when grouping enum values for . /// - public struct EnumGroupAndName + public readonly struct EnumGroupAndName { private readonly Func _name; diff --git a/src/Microsoft.AspNetCore.Mvc.Abstractions/ModelBinding/Metadata/ModelMetadataIdentity.cs b/src/Microsoft.AspNetCore.Mvc.Abstractions/ModelBinding/Metadata/ModelMetadataIdentity.cs index af97d9a043..655bd9cb74 100644 --- a/src/Microsoft.AspNetCore.Mvc.Abstractions/ModelBinding/Metadata/ModelMetadataIdentity.cs +++ b/src/Microsoft.AspNetCore.Mvc.Abstractions/ModelBinding/Metadata/ModelMetadataIdentity.cs @@ -11,8 +11,20 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata /// /// A key type which identifies a . /// - public struct ModelMetadataIdentity : IEquatable + public readonly struct ModelMetadataIdentity : IEquatable { + private ModelMetadataIdentity( + Type modelType, + string name = null, + Type containerType = null, + ParameterInfo parameterInfo = null) + { + ModelType = modelType; + Name = name; + ContainerType = containerType; + ParameterInfo = parameterInfo; + } + /// /// Creates a for the provided model . /// @@ -25,10 +37,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata throw new ArgumentNullException(nameof(modelType)); } - return new ModelMetadataIdentity() - { - ModelType = modelType, - }; + return new ModelMetadataIdentity(modelType); } /// @@ -58,12 +67,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, nameof(name)); } - return new ModelMetadataIdentity() - { - ModelType = modelType, - Name = name, - ContainerType = containerType, - }; + return new ModelMetadataIdentity(modelType, name, containerType); } /// @@ -93,24 +97,19 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata throw new ArgumentNullException(nameof(modelType)); } - return new ModelMetadataIdentity() - { - Name = parameter.Name, - ModelType = modelType, - ParameterInfo = parameter, - }; + return new ModelMetadataIdentity(modelType, parameter.Name, parameterInfo: parameter); } /// /// Gets the defining the model property represented by the current /// instance, or null if the current instance does not represent a property. /// - public Type ContainerType { get; private set; } + public Type ContainerType { get; } /// /// Gets the represented by the current instance. /// - public Type ModelType { get; private set; } + public Type ModelType { get; } /// /// Gets a value indicating the kind of metadata represented by the current instance. @@ -138,13 +137,13 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata /// Gets the name of the current instance if it represents a parameter or property, or null if /// the current instance represents a type. /// - public string Name { get; private set; } + public string Name { get; } /// /// Gets a descriptor for the parameter, or null if this instance /// does not represent a parameter. /// - public ParameterInfo ParameterInfo { get; private set; } + public ParameterInfo ParameterInfo { get; } /// public bool Equals(ModelMetadataIdentity other) diff --git a/src/Microsoft.AspNetCore.Mvc.Abstractions/ModelBinding/ModelBindingContext.cs b/src/Microsoft.AspNetCore.Mvc.Abstractions/ModelBinding/ModelBindingContext.cs index 50c0149cc2..e133b6816e 100644 --- a/src/Microsoft.AspNetCore.Mvc.Abstractions/ModelBinding/ModelBindingContext.cs +++ b/src/Microsoft.AspNetCore.Mvc.Abstractions/ModelBinding/ModelBindingContext.cs @@ -156,7 +156,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding /// by caller when child binding context state should be popped off of /// the . /// - public struct NestedScope : IDisposable + public readonly struct NestedScope : IDisposable { private readonly ModelBindingContext _context; diff --git a/src/Microsoft.AspNetCore.Mvc.Abstractions/ModelBinding/ModelBindingResult.cs b/src/Microsoft.AspNetCore.Mvc.Abstractions/ModelBinding/ModelBindingResult.cs index de57b8bf88..2bfc3dd5fd 100644 --- a/src/Microsoft.AspNetCore.Mvc.Abstractions/ModelBinding/ModelBindingResult.cs +++ b/src/Microsoft.AspNetCore.Mvc.Abstractions/ModelBinding/ModelBindingResult.cs @@ -9,7 +9,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding /// /// Contains the result of model binding. /// - public struct ModelBindingResult : IEquatable + public readonly struct ModelBindingResult : IEquatable { /// /// Creates a representing a failed model binding operation. diff --git a/src/Microsoft.AspNetCore.Mvc.Abstractions/ModelBinding/ModelStateDictionary.cs b/src/Microsoft.AspNetCore.Mvc.Abstractions/ModelBinding/ModelStateDictionary.cs index 970e5b6975..68781961e6 100644 --- a/src/Microsoft.AspNetCore.Mvc.Abstractions/ModelBinding/ModelStateDictionary.cs +++ b/src/Microsoft.AspNetCore.Mvc.Abstractions/ModelBinding/ModelStateDictionary.cs @@ -1003,7 +1003,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding } } - public struct PrefixEnumerable : IEnumerable> + public readonly struct PrefixEnumerable : IEnumerable> { private readonly ModelStateDictionary _dictionary; private readonly string _prefix; @@ -1136,7 +1136,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding } } - public struct KeyEnumerable : IEnumerable + public readonly struct KeyEnumerable : IEnumerable { private readonly ModelStateDictionary _dictionary; @@ -1191,7 +1191,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding } } - public struct ValueEnumerable : IEnumerable + public readonly struct ValueEnumerable : IEnumerable { private readonly ModelStateDictionary _dictionary; diff --git a/src/Microsoft.AspNetCore.Mvc.Abstractions/ModelBinding/ValueProviderResult.cs b/src/Microsoft.AspNetCore.Mvc.Abstractions/ModelBinding/ValueProviderResult.cs index c9bf19ad4c..3a0b8e1fa8 100644 --- a/src/Microsoft.AspNetCore.Mvc.Abstractions/ModelBinding/ValueProviderResult.cs +++ b/src/Microsoft.AspNetCore.Mvc.Abstractions/ModelBinding/ValueProviderResult.cs @@ -25,7 +25,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding /// regardless of whether a single value or multiple values were submitted. /// /// - public struct ValueProviderResult : IEquatable, IEnumerable + public readonly struct ValueProviderResult : IEquatable, IEnumerable { private static readonly CultureInfo _invariantCulture = CultureInfo.InvariantCulture; diff --git a/src/Microsoft.AspNetCore.Mvc.Analyzers.Experimental/ApiActionsAreAttributeRoutedFixProvider.cs b/src/Microsoft.AspNetCore.Mvc.Analyzers.Experimental/ApiActionsAreAttributeRoutedFixProvider.cs index a0ea810b51..f89827b8f0 100644 --- a/src/Microsoft.AspNetCore.Mvc.Analyzers.Experimental/ApiActionsAreAttributeRoutedFixProvider.cs +++ b/src/Microsoft.AspNetCore.Mvc.Analyzers.Experimental/ApiActionsAreAttributeRoutedFixProvider.cs @@ -168,7 +168,7 @@ namespace Microsoft.AspNetCore.Mvc.Analyzers return false; } - private struct RouteAttributeInfo + private readonly struct RouteAttributeInfo { public RouteAttributeInfo(string name, string type, string[] keywords) { diff --git a/src/Microsoft.AspNetCore.Mvc.ApiExplorer/DefaultApiDescriptionProvider.cs b/src/Microsoft.AspNetCore.Mvc.ApiExplorer/DefaultApiDescriptionProvider.cs index 46fa05fb5a..6fd8c7e65f 100644 --- a/src/Microsoft.AspNetCore.Mvc.ApiExplorer/DefaultApiDescriptionProvider.cs +++ b/src/Microsoft.AspNetCore.Mvc.ApiExplorer/DefaultApiDescriptionProvider.cs @@ -659,7 +659,7 @@ namespace Microsoft.AspNetCore.Mvc.ApiExplorer } } - private struct PropertyKey + private readonly struct PropertyKey { public readonly Type ContainerType; diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Formatters/MediaType.cs b/src/Microsoft.AspNetCore.Mvc.Core/Formatters/MediaType.cs index 00e2459f09..7c557ed4cc 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/Formatters/MediaType.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/Formatters/MediaType.cs @@ -13,7 +13,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters /// /// A media type value. /// - public struct MediaType + public readonly struct MediaType { private static readonly StringSegment QualityParameter = new StringSegment("q"); @@ -683,7 +683,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters } } - private struct MediaTypeParameter : IEquatable + private readonly struct MediaTypeParameter : IEquatable { public MediaTypeParameter(StringSegment name, StringSegment value) { diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Internal/ClientValidatorCache.cs b/src/Microsoft.AspNetCore.Mvc.Core/Internal/ClientValidatorCache.cs index 37adde40c2..0bcc97f67b 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/Internal/ClientValidatorCache.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/Internal/ClientValidatorCache.cs @@ -121,7 +121,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal return validators; } - private struct CacheEntry + private readonly struct CacheEntry { public CacheEntry(IReadOnlyList validators) { diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Internal/ControllerBinderDelegateProvider.cs b/src/Microsoft.AspNetCore.Mvc.Core/Internal/ControllerBinderDelegateProvider.cs index e29525ea11..20d600281e 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/Internal/ControllerBinderDelegateProvider.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/Internal/ControllerBinderDelegateProvider.cs @@ -194,7 +194,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal return propertyBindingInfo; } - private struct BinderItem + private readonly struct BinderItem { public BinderItem(IModelBinder modelBinder, ModelMetadata modelMetadata) { diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Internal/FilterCursorItem.cs b/src/Microsoft.AspNetCore.Mvc.Core/Internal/FilterCursorItem.cs index ccb42dc3f7..a62aa1b8cc 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/Internal/FilterCursorItem.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/Internal/FilterCursorItem.cs @@ -3,7 +3,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal { - public struct FilterCursorItem + public readonly struct FilterCursorItem { public FilterCursorItem(TFilter filter, TFilterAsync filterAsync) { diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Internal/FilterFactoryResult.cs b/src/Microsoft.AspNetCore.Mvc.Core/Internal/FilterFactoryResult.cs index e532a08427..69e39cfea9 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/Internal/FilterFactoryResult.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/Internal/FilterFactoryResult.cs @@ -5,7 +5,7 @@ using Microsoft.AspNetCore.Mvc.Filters; namespace Microsoft.AspNetCore.Mvc.Internal { - public struct FilterFactoryResult + public readonly struct FilterFactoryResult { public FilterFactoryResult( FilterItem[] cacheableFilters, diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Internal/MediaTypeSegmentWithQuality.cs b/src/Microsoft.AspNetCore.Mvc.Core/Internal/MediaTypeSegmentWithQuality.cs index c9a8f4502e..52d6281ed1 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/Internal/MediaTypeSegmentWithQuality.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/Internal/MediaTypeSegmentWithQuality.cs @@ -8,7 +8,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Internal /// /// A media type with its associated quality. /// - public struct MediaTypeSegmentWithQuality + public readonly struct MediaTypeSegmentWithQuality { /// /// Initializes an instance of . diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Internal/ValidatorCache.cs b/src/Microsoft.AspNetCore.Mvc.Core/Internal/ValidatorCache.cs index 61fcfe0c15..61e8303d40 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/Internal/ValidatorCache.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/Internal/ValidatorCache.cs @@ -122,7 +122,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal return validators; } - private struct CacheEntry + private readonly struct CacheEntry { public CacheEntry(IReadOnlyList validators) { diff --git a/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Metadata/DefaultModelMetadataProvider.cs b/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Metadata/DefaultModelMetadataProvider.cs index b9e374701e..75bd188997 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Metadata/DefaultModelMetadataProvider.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Metadata/DefaultModelMetadataProvider.cs @@ -345,7 +345,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata { } - private struct ModelMetadataCacheEntry + private readonly struct ModelMetadataCacheEntry { public ModelMetadataCacheEntry(ModelMetadata metadata, DefaultMetadataDetails details) { diff --git a/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/ModelBinderFactory.cs b/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/ModelBinderFactory.cs index 08e6883dd8..4b7a53b498 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/ModelBinderFactory.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/ModelBinderFactory.cs @@ -310,7 +310,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding // the ParameterDescriptor) or in a call to TryUpdateModel (no BindingInfo) or as a collection element. // // We need to be able to tell the difference between these things to avoid over-caching. - private struct Key : IEquatable + private readonly struct Key : IEquatable { private readonly ModelMetadata _metadata; private readonly object _token; // Explicitly using ReferenceEquality for tokens. diff --git a/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Validation/ValidationVisitor.cs b/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Validation/ValidationVisitor.cs index 43c385ec7b..fa467588a8 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Validation/ValidationVisitor.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Validation/ValidationVisitor.cs @@ -318,7 +318,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Validation return entry; } - protected struct StateManager : IDisposable + protected readonly struct StateManager : IDisposable { private readonly ValidationVisitor _visitor; private readonly object _container; diff --git a/src/Microsoft.AspNetCore.Mvc.Razor/Internal/ViewLocationCacheItem.cs b/src/Microsoft.AspNetCore.Mvc.Razor/Internal/ViewLocationCacheItem.cs index 23fe788101..64333eb02f 100644 --- a/src/Microsoft.AspNetCore.Mvc.Razor/Internal/ViewLocationCacheItem.cs +++ b/src/Microsoft.AspNetCore.Mvc.Razor/Internal/ViewLocationCacheItem.cs @@ -8,7 +8,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal /// /// An item in . /// - public struct ViewLocationCacheItem + public readonly struct ViewLocationCacheItem { /// /// Initializes a new instance of . diff --git a/src/Microsoft.AspNetCore.Mvc.Razor/Internal/ViewLocationCacheKey.cs b/src/Microsoft.AspNetCore.Mvc.Razor/Internal/ViewLocationCacheKey.cs index 7643882f79..00f3d3c8ec 100644 --- a/src/Microsoft.AspNetCore.Mvc.Razor/Internal/ViewLocationCacheKey.cs +++ b/src/Microsoft.AspNetCore.Mvc.Razor/Internal/ViewLocationCacheKey.cs @@ -10,7 +10,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal /// /// Key for entries in . /// - public struct ViewLocationCacheKey : IEquatable + public readonly struct ViewLocationCacheKey : IEquatable { /// /// Initializes a new instance of . diff --git a/src/Microsoft.AspNetCore.Mvc.Razor/RazorPageFactoryResult.cs b/src/Microsoft.AspNetCore.Mvc.Razor/RazorPageFactoryResult.cs index 31f7b1ce94..45537550f7 100644 --- a/src/Microsoft.AspNetCore.Mvc.Razor/RazorPageFactoryResult.cs +++ b/src/Microsoft.AspNetCore.Mvc.Razor/RazorPageFactoryResult.cs @@ -9,7 +9,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor /// /// Result of . /// - public struct RazorPageFactoryResult + public readonly struct RazorPageFactoryResult { /// /// Initializes a new instance of with the diff --git a/src/Microsoft.AspNetCore.Mvc.Razor/RazorPageResult.cs b/src/Microsoft.AspNetCore.Mvc.Razor/RazorPageResult.cs index c299e350fe..044e3ee581 100644 --- a/src/Microsoft.AspNetCore.Mvc.Razor/RazorPageResult.cs +++ b/src/Microsoft.AspNetCore.Mvc.Razor/RazorPageResult.cs @@ -9,7 +9,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor /// /// Result of locating a . /// - public struct RazorPageResult + public readonly struct RazorPageResult { /// /// Initializes a new instance of for a successful discovery. diff --git a/src/Microsoft.AspNetCore.Mvc.RazorPages/Internal/PageBinderFactory.cs b/src/Microsoft.AspNetCore.Mvc.RazorPages/Internal/PageBinderFactory.cs index 6fcc9e08c8..72fd33d754 100644 --- a/src/Microsoft.AspNetCore.Mvc.RazorPages/Internal/PageBinderFactory.cs +++ b/src/Microsoft.AspNetCore.Mvc.RazorPages/Internal/PageBinderFactory.cs @@ -163,7 +163,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal } } - private struct BinderItem + private readonly struct BinderItem { public BinderItem(IModelBinder modelBinder, ModelMetadata modelMetadata) { diff --git a/src/Microsoft.AspNetCore.Mvc.TagHelpers/Internal/GlobbingUrlBuilder.cs b/src/Microsoft.AspNetCore.Mvc.TagHelpers/Internal/GlobbingUrlBuilder.cs index 9b756848a1..ce891ad84e 100644 --- a/src/Microsoft.AspNetCore.Mvc.TagHelpers/Internal/GlobbingUrlBuilder.cs +++ b/src/Microsoft.AspNetCore.Mvc.TagHelpers/Internal/GlobbingUrlBuilder.cs @@ -352,7 +352,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers.Internal return new StringSegment(value.Buffer, offset, trimmedEnd - offset + 1); } - private struct GlobbingUrlKey : IEquatable + private readonly struct GlobbingUrlKey : IEquatable { public GlobbingUrlKey(string include, string exclude) { diff --git a/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Internal/ViewBufferValue.cs b/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Internal/ViewBufferValue.cs index 89c9581848..68691a9868 100644 --- a/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Internal/ViewBufferValue.cs +++ b/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Internal/ViewBufferValue.cs @@ -12,7 +12,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal /// Encapsulates a string or value. /// [DebuggerDisplay("{DebuggerToString()}")] - public struct ViewBufferValue + public readonly struct ViewBufferValue { /// /// Initializes a new instance of with a string value. @@ -41,15 +41,13 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal { using (var writer = new StringWriter()) { - var valueAsString = Value as string; - if (valueAsString != null) + if (Value is string valueAsString) { writer.Write(valueAsString); return writer.ToString(); } - var valueAsContent = Value as IHtmlContent; - if (valueAsContent != null) + if (Value is IHtmlContent valueAsContent) { valueAsContent.WriteTo(writer, HtmlEncoder.Default); return writer.ToString(); diff --git a/src/Microsoft.AspNetCore.Mvc.ViewFeatures/ViewFeatures/MemberExpressionCacheKey.cs b/src/Microsoft.AspNetCore.Mvc.ViewFeatures/ViewFeatures/MemberExpressionCacheKey.cs index 1cbc80c38a..8f8b667983 100644 --- a/src/Microsoft.AspNetCore.Mvc.ViewFeatures/ViewFeatures/MemberExpressionCacheKey.cs +++ b/src/Microsoft.AspNetCore.Mvc.ViewFeatures/ViewFeatures/MemberExpressionCacheKey.cs @@ -8,7 +8,7 @@ using System.Reflection; namespace Microsoft.AspNetCore.Mvc.ViewFeatures { - internal struct MemberExpressionCacheKey + internal readonly struct MemberExpressionCacheKey { public MemberExpressionCacheKey(Type modelType, MemberExpression memberExpression) { @@ -44,7 +44,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures public MemberInfo[] Members { get; } - public Enumerator GetEnumerator() => new Enumerator(ref this); + public Enumerator GetEnumerator() => new Enumerator(this); public struct Enumerator { @@ -52,7 +52,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures private int _index; private MemberExpression _memberExpression; - public Enumerator(ref MemberExpressionCacheKey key) + public Enumerator(in MemberExpressionCacheKey key) { Current = null; _members = key.Members; From ce8fc29728394ddf104bdfc1bf164a7895e5f7ae Mon Sep 17 00:00:00 2001 From: Pranav K Date: Thu, 2 Aug 2018 15:36:27 -0700 Subject: [PATCH 2/2] ConsumesAttribute accepts requests without content type Fixes #8174 --- .../ConsumesAttribute.cs | 4 +--- .../ConsumesAttributeTests.cs | 5 +++-- .../ConsumesAttributeEndpointRoutingTests.cs | 18 ------------------ .../ConsumesAttributeTestsBase.cs | 8 ++------ 4 files changed, 6 insertions(+), 29 deletions(-) diff --git a/src/Microsoft.AspNetCore.Mvc.Core/ConsumesAttribute.cs b/src/Microsoft.AspNetCore.Mvc.Core/ConsumesAttribute.cs index 8a6efd7362..7af167dc51 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/ConsumesAttribute.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/ConsumesAttribute.cs @@ -10,8 +10,6 @@ using Microsoft.AspNetCore.Mvc.ApiExplorer; using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.AspNetCore.Mvc.Formatters; using Microsoft.AspNetCore.Mvc.Internal; -using Microsoft.AspNetCore.Mvc.Routing; -using Microsoft.AspNetCore.Routing; using Microsoft.Net.Http.Headers; using Resources = Microsoft.AspNetCore.Mvc.Core.Resources; @@ -79,7 +77,7 @@ namespace Microsoft.AspNetCore.Mvc // Confirm the request's content type is more specific than a media type this action supports e.g. OK // if client sent "text/plain" data and this action supports "text/*". - if (requestContentType != null && !IsSubsetOfAnyContentType(requestContentType)) + if (requestContentType == null || !IsSubsetOfAnyContentType(requestContentType)) { context.Result = new UnsupportedMediaTypeResult(); } diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/ConsumesAttributeTests.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/ConsumesAttributeTests.cs index 57a0bbddf1..be1999d28d 100644 --- a/test/Microsoft.AspNetCore.Mvc.Core.Test/ConsumesAttributeTests.cs +++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/ConsumesAttributeTests.cs @@ -326,7 +326,7 @@ namespace Microsoft.AspNetCore.Mvc [Theory] [InlineData("")] [InlineData(null)] - public void OnResourceExecuting_NullOrEmptyRequestContentType_IsNoOp(string contentType) + public void OnResourceExecuting_NullOrEmptyRequestContentType_SetsUnsupportedMediaTypeResult(string contentType) { // Arrange var httpContext = new DefaultHttpContext(); @@ -349,7 +349,8 @@ namespace Microsoft.AspNetCore.Mvc consumesFilter.OnResourceExecuting(resourceExecutingContext); // Assert - Assert.Null(resourceExecutingContext.Result); + Assert.NotNull(resourceExecutingContext.Result); + Assert.IsType(resourceExecutingContext.Result); } [Theory] diff --git a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/ConsumesAttributeEndpointRoutingTests.cs b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/ConsumesAttributeEndpointRoutingTests.cs index 9aebbcb2d4..7377442ac6 100644 --- a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/ConsumesAttributeEndpointRoutingTests.cs +++ b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/ConsumesAttributeEndpointRoutingTests.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Net; -using System.Net.Http; using System.Threading.Tasks; using Newtonsoft.Json; using Xunit; @@ -30,22 +29,5 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests Assert.True(result); } - - // The endpoint routing version of this feature has fixed https://github.com/aspnet/Mvc/issues/8174 - [Fact] - public override async Task NoRequestContentType_Selects_IfASingleActionWithConstraintIsPresent() - { - // Arrange - var request = new HttpRequestMessage( - HttpMethod.Post, - "http://localhost/ConsumesAttribute_PassThrough/CreateProduct"); - - // Act - var response = await Client.SendAsync(request); - var body = await response.Content.ReadAsStringAsync(); - - // Assert - Assert.Equal(HttpStatusCode.UnsupportedMediaType, response.StatusCode); - } } } \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/ConsumesAttributeTestsBase.cs b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/ConsumesAttributeTestsBase.cs index 302d50fc9d..fca64c9dc4 100644 --- a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/ConsumesAttributeTestsBase.cs +++ b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/ConsumesAttributeTestsBase.cs @@ -49,7 +49,7 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests } [Fact] - public virtual async Task NoRequestContentType_Selects_IfASingleActionWithConstraintIsPresent() + public async Task NoRequestContentType_Selects_IfASingleActionWithConstraintIsPresent_ReturnsUnsupported() { // Arrange var request = new HttpRequestMessage( @@ -58,11 +58,7 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests // Act var response = await Client.SendAsync(request); - var body = await response.Content.ReadAsStringAsync(); - - // Assert - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.Equal("ConsumesAttribute_PassThrough_Product_Json", body); + await response.AssertStatusCodeAsync(HttpStatusCode.UnsupportedMediaType); } [Theory]