Add some reference docs for MVC (#7981)

This commit is contained in:
Pranav K 2019-02-28 09:56:55 -08:00 committed by GitHub
parent 3d2946060f
commit f79f2e3b12
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
39 changed files with 554 additions and 19 deletions

View File

@ -9,8 +9,14 @@ using Microsoft.AspNetCore.Mvc.Routing;
namespace Microsoft.AspNetCore.Mvc.Abstractions
{
/// <summary>
/// Describes a MVC action.
/// </summary>
public class ActionDescriptor
{
/// <summary>
/// Initializes a new instance of <see cref="ActionDescriptor"/>.
/// </summary>
public ActionDescriptor()
{
Id = Guid.NewGuid().ToString();
@ -29,6 +35,9 @@ namespace Microsoft.AspNetCore.Mvc.Abstractions
/// </summary>
public IDictionary<string, string> RouteValues { get; set; }
/// <summary>
/// Gets or sets the <see cref="Routing.AttributeRouteInfo"/>.
/// </summary>
public AttributeRouteInfo AttributeRouteInfo { get; set; }
/// <summary>

View File

@ -5,8 +5,15 @@ using System.Collections.Generic;
namespace Microsoft.AspNetCore.Mvc.Abstractions
{
/// <summary>
/// A context for <see cref="IActionDescriptorProvider"/>.
/// </summary>
public class ActionDescriptorProviderContext
{
/// <summary>
/// Gets the <see cref="IList{T}" /> of <see cref="ActionDescriptor"/> instances of <see cref="IActionDescriptorProvider"/>
/// can populate.
/// </summary>
public IList<ActionDescriptor> Results { get; } = new List<ActionDescriptor>();
}
}

View File

@ -5,8 +5,15 @@ using System;
namespace Microsoft.AspNetCore.Mvc.Abstractions
{
/// <summary>
/// A context for <see cref="IActionInvokerProvider"/>.
/// </summary>
public class ActionInvokerProviderContext
{
/// <summary>
/// Initializes a new instance of <see cref="ActionInvokerProviderContext"/>.
/// </summary>
/// <param name="actionContext">The <see cref="Mvc.ActionContext"/> to invoke.</param>
public ActionInvokerProviderContext(ActionContext actionContext)
{
if (actionContext == null)
@ -17,8 +24,14 @@ namespace Microsoft.AspNetCore.Mvc.Abstractions
ActionContext = actionContext;
}
/// <summary>
/// Gets the <see cref="Mvc.ActionContext"/> to invoke.
/// </summary>
public ActionContext ActionContext { get; }
/// <summary>
/// Gets or sets the <see cref="IActionInvoker"/> that will be used to invoke <see cref="ActionContext" />
/// </summary>
public IActionInvoker Result { get; set; }
}
}

View File

@ -3,6 +3,26 @@
namespace Microsoft.AspNetCore.Mvc.Abstractions
{
/// <summary>
/// Defines a contract for specifying <see cref="ActionDescriptor"/> instances.
/// </summary>
/// <remarks>
/// <para>
/// On application initialization, MVC invokes all registered instances of <see cref="IActionDescriptorProvider"/> to
/// perform <see cref="ActionDescriptor" /> discovery.
/// <see cref="IActionDescriptorProvider"/> instances are invoked in the ascending sort order of <see cref="Order"/>.
/// </para>
/// <para>
/// Each provider has its <see cref="OnProvidersExecuting"/> method
/// called in sequence and given the same instance of <see cref="ActionInvokerProviderContext"/>. Then each
/// provider has its <see cref="OnProvidersExecuted"/> method called in the reverse order. Each instance has
/// an opportunity to add or modify <see cref="ActionDescriptorProviderContext.Results"/>.
/// </para>
/// <para>
/// As providers are called in a predefined sequence, each provider has a chance to observe and decorate the
/// result of the providers that have already run.
/// </para>
/// </remarks>
public interface IActionDescriptorProvider
{
/// <summary>
@ -26,8 +46,19 @@ namespace Microsoft.AspNetCore.Mvc.Abstractions
/// </remarks>
int Order { get; }
/// <summary>
/// Called to execute the provider.
/// <see cref="Order"/> for details on the order of execution of <see cref="OnProvidersExecuting(ActionDescriptorProviderContext)"/>.
/// </summary>
/// <param name="context">The <see cref="ActionDescriptorProviderContext"/>.</param>
void OnProvidersExecuting(ActionDescriptorProviderContext context);
/// <summary>
/// Called to execute the provider, after the <see cref="OnProvidersExecuting"/> methods of all providers,
/// have been called.
/// <see cref="Order"/> for details on the order of execution of <see cref="OnProvidersExecuted(ActionDescriptorProviderContext)"/>.
/// </summary>
/// <param name="context">The <see cref="ActionDescriptorProviderContext"/>.</param>
void OnProvidersExecuted(ActionDescriptorProviderContext context);
}
}

View File

@ -6,12 +6,24 @@ using Microsoft.AspNetCore.Mvc.ModelBinding;
namespace Microsoft.AspNetCore.Mvc.Abstractions
{
/// <summary>
/// Describes a parameter in an action.
/// </summary>
public class ParameterDescriptor
{
/// <summary>
/// Gets or sets the parameter name.
/// </summary>
public string Name { get; set; }
/// <summary>
/// Gets or sets the type of the parameter.
/// </summary>
public Type ParameterType { get; set; }
/// <summary>
/// Gets or sets the <see cref="ModelBinding.BindingInfo"/> for the parameter.
/// </summary>
public BindingInfo BindingInfo { get; set; }
}
}

View File

@ -3,6 +3,9 @@
namespace Microsoft.AspNetCore.Mvc.ActionConstraints
{
/// <summary>
/// Provider for <see cref="IActionConstraint"/>.
/// </summary>
public interface IActionConstraintProvider
{
/// <summary>
@ -26,8 +29,19 @@ namespace Microsoft.AspNetCore.Mvc.ActionConstraints
/// </remarks>
int Order { get; }
/// <summary>
/// Called to execute the provider.
/// <see cref="Order"/> for details on the order of execution of <see cref="OnProvidersExecuting(ActionConstraintProviderContext)"/>.
/// </summary>
/// <param name="context">The <see cref="ActionConstraintProviderContext"/>.</param>
void OnProvidersExecuting(ActionConstraintProviderContext context);
/// <summary>
/// Called to execute the provider, after the <see cref="OnProvidersExecuting"/> methods of all providers,
/// have been called.
/// <see cref="Order"/> for details on the order of execution of <see cref="OnProvidersExecuted(ActionConstraintProviderContext)"/>.
/// </summary>
/// <param name="context">The <see cref="ActionConstraintProviderContext"/>.</param>
void OnProvidersExecuted(ActionConstraintProviderContext context);
}
}

View File

@ -1,8 +1,29 @@
// 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.Mvc.Abstractions;
namespace Microsoft.AspNetCore.Mvc.ApiExplorer
{
/// <summary>
/// Defines a contract for specifying <see cref="ApiDescription"/> instances.
/// </summary>
/// <remarks>
/// <para>
/// On the first query for <see cref="ActionDescriptor"/>, MVC invokes all registered instances of <see cref="IApiDescriptionProvider"/>
/// in the ascending sort order of <see cref="Order"/>.
/// </para>
/// <para>
/// Each provider has its <see cref="OnProvidersExecuting"/> method
/// called in sequence and given the same instance of <see cref="ApiDescriptionProviderContext"/>. Then each
/// provider has its <see cref="OnProvidersExecuted"/> method called in the reverse order. Each instance has
/// an opportunity to add or modify <see cref="ApiDescriptionProviderContext.Results"/>.
/// </para>
/// <para>
/// As providers are called in a predefined sequence, each provider has a chance to observe and decorate the
/// result of the providers that have already run.
/// </para>
/// </remarks>
public interface IApiDescriptionProvider
{
/// <summary>

View File

@ -10,15 +10,28 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
/// </summary>
public class InputFormatterException : Exception
{
/// <summary>
/// Initializes a new instance of <see cref="InputFormatterException"/>.
/// </summary>
public InputFormatterException()
{
}
/// <summary>
/// Initializes a new instance of <see cref="InputFormatterException"/> with the specified <paramref name="message"/>.
/// </summary>
/// <param name="message">The exception message.</param>
public InputFormatterException(string message)
: base(message)
{
}
/// <summary>
/// Initializes a new instance of <see cref="InputFormatterException"/> with the specified <paramref name="message"/> and
/// inner exception that is the cause of this exception.
/// </summary>
/// <param name="message">The exception message.</param>
/// <param name="innerException">The exception that is the cause of the current exception.</param>
public InputFormatterException(string message, Exception innerException)
: base(message, innerException)
{

View File

@ -6,7 +6,6 @@ Commonly used types:
Microsoft.AspNetCore.Mvc.IActionResult</Description>
<TargetFramework>netcoreapp3.0</TargetFramework>
<IsAspNetCoreApp>true</IsAspNetCoreApp>
<NoWarn>$(NoWarn);CS1591</NoWarn>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageTags>aspnetcore;aspnetcoremvc</PackageTags>
</PropertyGroup>

View File

@ -6,10 +6,26 @@ using System.Collections.Generic;
namespace Microsoft.AspNetCore.Mvc.ModelBinding
{
/// <summary>
/// A provider that can supply instances of <see cref="ModelMetadata"/>.
/// </summary>
/// <remarks>
/// While not obsolete, implementing or using <see cref="ModelMetadataProvider" /> is preferred over <see cref="IModelMetadataProvider"/>.
/// </remarks>
public interface IModelMetadataProvider
{
/// <summary>
/// Supplies metadata describing a <see cref="Type"/>.
/// </summary>
/// <param name="modelType">The <see cref="Type"/>.</param>
/// <returns>A <see cref="ModelMetadata"/> instance describing the <see cref="Type"/>.</returns>
ModelMetadata GetMetadataForType(Type modelType);
/// <summary>
/// Supplies metadata describing the properties of a <see cref="Type"/>.
/// </summary>
/// <param name="modelType">The <see cref="Type"/>.</param>
/// <returns>A set of <see cref="ModelMetadata"/> instances describing properties of the <see cref="Type"/>.</returns>
IEnumerable<ModelMetadata> GetMetadataForProperties(Type modelType);
}
}

View File

@ -5,35 +5,49 @@ using System;
namespace Microsoft.AspNetCore.Mvc.ModelBinding
{
/// <summary>
/// An error that occured during model binding and validation.
/// </summary>
public class ModelError
{
/// <summary>
/// Intiializes a new instance of <see cref="ModelError"/> with the specified <paramref name="exception"/>.
/// </summary>
/// <param name="exception">The <see cref="System.Exception"/>.</param>
public ModelError(Exception exception)
: this(exception, errorMessage: null)
{
if (exception == null)
{
throw new ArgumentNullException(nameof(exception));
}
}
/// <summary>
/// Intiializes a new instance of <see cref="ModelError"/> with the specified <paramref name="exception"/>
/// and specified <paramref name="errorMessage"/>.
/// </summary>
/// <param name="exception">The <see cref="System.Exception"/>.</param>
/// <param name="errorMessage">The error message.</param>
public ModelError(Exception exception, string errorMessage)
: this(errorMessage)
{
if (exception == null)
{
throw new ArgumentNullException(nameof(exception));
}
Exception = exception;
Exception = exception ?? throw new ArgumentNullException(nameof(exception));
}
/// <summary>
/// Initializes a new instance of <see cref="ModelError"/> with the specified <paramref name="errorMessage"/>.
/// </summary>
/// <param name="errorMessage">The error message.</param>
public ModelError(string errorMessage)
{
ErrorMessage = errorMessage ?? string.Empty;
}
/// <summary>
/// Gets the <see cref="System.Exception"/> associated with this <see cref="ModelError"/> instance.
/// </summary>
public Exception Exception { get; }
/// <summary>
/// Gets the error message associated with this <see cref="ModelError"/> instance.
/// </summary>
public string ErrorMessage { get; }
}
}

View File

@ -6,8 +6,15 @@ using System.Collections.ObjectModel;
namespace Microsoft.AspNetCore.Mvc.ModelBinding
{
/// <summary>
/// A collection of <see cref="ModelError"/> instances.
/// </summary>
public class ModelErrorCollection : Collection<ModelError>
{
/// <summary>
/// Adds the specified <paramref name="exception"/> instance.
/// </summary>
/// <param name="exception">The <see cref="Exception"/></param>
public void Add(Exception exception)
{
if (exception == null)
@ -18,6 +25,10 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
Add(new ModelError(exception));
}
/// <summary>
/// Adds the specified error message.
/// </summary>
/// <param name="errorMessage">The error message.</param>
public void Add(string errorMessage)
{
if (errorMessage == null)

View File

@ -797,6 +797,12 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
/// <inheritdoc />
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
/// <summary>
/// <para>
/// This API supports the MVC's infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </para>
/// </summary>
public static bool StartsWithPrefix(string prefix, string key)
{
if (prefix == null)
@ -840,6 +846,12 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
return false;
}
/// <summary>
/// Gets a <see cref="PrefixEnumerable"/> that iterates over this instance of <see cref="ModelStateDictionary"/>
/// using the specified <paramref name="prefix"/>.
/// </summary>
/// <param name="prefix">The prefix.</param>
/// <returns>The <see cref="PrefixEnumerable"/>.</returns>
public PrefixEnumerable FindKeysWithPrefix(string prefix)
{
if (prefix == null)
@ -1004,11 +1016,20 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
}
}
/// <summary>
/// Enumerates over <see cref="ModelStateDictionary"/> to provide entries that start with the
/// specified prefix.
/// </summary>
public readonly struct PrefixEnumerable : IEnumerable<KeyValuePair<string, ModelStateEntry>>
{
private readonly ModelStateDictionary _dictionary;
private readonly string _prefix;
/// <summary>
/// Initializes a new instance of <see cref="PrefixEnumerable"/>.
/// </summary>
/// <param name="dictionary">The <see cref="ModelStateDictionary"/>.</param>
/// <param name="prefix">The prefix.</param>
public PrefixEnumerable(ModelStateDictionary dictionary, string prefix)
{
if (dictionary == null)
@ -1025,6 +1046,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
_prefix = prefix;
}
/// <inheritdoc />
public Enumerator GetEnumerator() => new Enumerator(_dictionary, _prefix);
IEnumerator<KeyValuePair<string, ModelStateEntry>>
@ -1033,6 +1055,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
/// <summary>
/// An <see cref="IEnumerator{T}"/> for <see cref="PrefixEnumerable"/>.
/// </summary>
public struct Enumerator : IEnumerator<KeyValuePair<string, ModelStateEntry>>
{
private readonly ModelStateNode _rootNode;
@ -1041,6 +1066,11 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
private int _index;
private bool _visitedRoot;
/// <summary>
/// Intializes a new instance of <see cref="Enumerator"/>.
/// </summary>
/// <param name="dictionary">The <see cref="ModelStateDictionary"/>.</param>
/// <param name="prefix">The prefix.</param>
public Enumerator(ModelStateDictionary dictionary, string prefix)
{
if (dictionary == null)
@ -1059,16 +1089,19 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
_nodes = null;
_visitedRoot = false;
}
/// <inheritdoc />
public KeyValuePair<string, ModelStateEntry> Current =>
new KeyValuePair<string, ModelStateEntry>(_modelStateNode.Key, _modelStateNode);
object IEnumerator.Current => Current;
/// <inheritdoc />
public void Dispose()
{
}
/// <inheritdoc />
public bool MoveNext()
{
if (_rootNode == null)
@ -1128,6 +1161,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
return false;
}
/// <inheritdoc />
public void Reset()
{
_index = -1;
@ -1137,15 +1171,23 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
}
}
/// <summary>
/// A <see cref="IEnumerable{T}"/> for keys in <see cref="ModelStateDictionary"/>.
/// </summary>
public readonly struct KeyEnumerable : IEnumerable<string>
{
private readonly ModelStateDictionary _dictionary;
/// <summary>
/// Initializes a new instance of <see cref="KeyEnumerable"/>.
/// </summary>
/// <param name="dictionary">The <see cref="ModelStateDictionary"/>.</param>
public KeyEnumerable(ModelStateDictionary dictionary)
{
_dictionary = dictionary;
}
/// <inheritdoc />
public KeyEnumerator GetEnumerator() => new KeyEnumerator(_dictionary, prefix: string.Empty);
IEnumerator<string> IEnumerable<string>.GetEnumerator() => GetEnumerator();
@ -1153,22 +1195,33 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
/// <summary>
/// An <see cref="IEnumerator{T}"/> for keys in <see cref="ModelStateDictionary"/>.
/// </summary>
public struct KeyEnumerator : IEnumerator<string>
{
private Enumerator _prefixEnumerator;
/// <summary>
/// Initializes a new instance of <see cref="KeyEnumerable"/>.
/// </summary>
/// <param name="dictionary">The <see cref="ModelStateDictionary"/>.</param>
/// <param name="prefix">The prefix.</param>
public KeyEnumerator(ModelStateDictionary dictionary, string prefix)
{
_prefixEnumerator = new Enumerator(dictionary, prefix);
Current = null;
}
/// <inheritdoc />
public string Current { get; private set; }
object IEnumerator.Current => Current;
/// <inheritdoc />
public void Dispose() => _prefixEnumerator.Dispose();
/// <inheritdoc />
public bool MoveNext()
{
var result = _prefixEnumerator.MoveNext();
@ -1185,6 +1238,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
return result;
}
/// <inheritdoc />
public void Reset()
{
_prefixEnumerator.Reset();
@ -1192,15 +1246,23 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
}
}
/// <summary>
/// An <see cref="IEnumerable"/> for <see cref="ModelStateEntry"/>.
/// </summary>
public readonly struct ValueEnumerable : IEnumerable<ModelStateEntry>
{
private readonly ModelStateDictionary _dictionary;
/// <summary>
/// Initializes a new instance of <see cref="ValueEnumerable"/>.
/// </summary>
/// <param name="dictionary">The <see cref="ModelStateDictionary"/>.</param>
public ValueEnumerable(ModelStateDictionary dictionary)
{
_dictionary = dictionary;
}
/// <inheritdoc />
public ValueEnumerator GetEnumerator() => new ValueEnumerator(_dictionary, prefix: string.Empty);
IEnumerator<ModelStateEntry> IEnumerable<ModelStateEntry>.GetEnumerator() => GetEnumerator();
@ -1208,22 +1270,33 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
/// <summary>
/// An enumerator for <see cref="ModelStateEntry"/>.
/// </summary>
public struct ValueEnumerator : IEnumerator<ModelStateEntry>
{
private Enumerator _prefixEnumerator;
/// <summary>
/// Initializes a new instance of <see cref="ValueEnumerator"/>.
/// </summary>
/// <param name="dictionary">The <see cref="ModelStateDictionary"/>.</param>
/// <param name="prefix">The prefix to enumerate.</param>
public ValueEnumerator(ModelStateDictionary dictionary, string prefix)
{
_prefixEnumerator = new Enumerator(dictionary, prefix);
Current = null;
}
/// <inheritdoc />
public ModelStateEntry Current { get; private set; }
object IEnumerator.Current => Current;
/// <inheritdoc />
public void Dispose() => _prefixEnumerator.Dispose();
/// <inheritdoc />
public bool MoveNext()
{
var result = _prefixEnumerator.MoveNext();
@ -1240,6 +1313,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
return result;
}
/// <inheritdoc />
public void Reset()
{
_prefixEnumerator.Reset();

View File

@ -3,11 +3,50 @@
namespace Microsoft.AspNetCore.Mvc.ModelBinding
{
/// <summary>
/// The validation state of a <see cref="ModelStateEntry"/> instance.
/// <para>
/// <see cref="ModelValidationState"/> of <see cref="ModelStateDictionary.Root"/> is used to determine the validity
/// of <see cref="ModelStateDictionary"/>. <see cref="ModelStateDictionary.IsValid"/> is <see langword="true" />, when
/// the aggregate validity (<see cref="ModelStateDictionary.GetFieldValidationState(string)"/>)
/// of the root node is <see cref="Valid"/>.
/// </para>
/// </summary>
public enum ModelValidationState
{
/// <summary>
/// Validation has not been performed on the <see cref="ModelStateEntry"/>.
/// <para>
/// For aggregate validity, the validation of a <see cref="ModelStateEntry"/> is <see cref="Unvalidated"/>
/// if either the entry or one of thedescendants is <see cref="Unvalidated"/>.
/// </para>
/// </summary>
Unvalidated,
/// <summary>
/// Validation was performed on the <see cref="ModelStateEntry"/> and was found to be invalid.
/// <para>
/// For aggregate validity, the validation of a <see cref="ModelStateEntry"/> is <see cref="Invalid"/>
/// if either the entry or one of the descendants is <see cref="Invalid"/> and none are <see cref="Unvalidated"/>.
/// </para>
/// </summary>
Invalid,
/// <summary>
/// Validation was performed on the <see cref="ModelStateEntry"/>
/// <para>
/// For aggregate validity, the validation of a <see cref="ModelStateEntry"/> is <see cref="Valid"/>
/// if the validity of the entry and all descendants is either <see cref="Valid"/> or <see cref="Skipped"/>.
/// </para>
/// </summary>
Valid,
/// <summary>
/// Validation was skipped for the <see cref="ModelStateEntry"/>.
/// <para>
/// The aggregate validity of an entry is never <see cref="Skipped"/>.
/// </para>
/// </summary>
Skipped
}
}

View File

@ -3,8 +3,20 @@
namespace Microsoft.AspNetCore.Mvc.ModelBinding.Validation
{
/// <summary>
/// Specifies the contract for performing validation in the browser.
/// <para>
/// MVC's validation system invokes <see cref="IClientModelValidator"/> to gather attributes that apply to the
/// rendered HTML. The rendered view may have to reference JavaScript libraries, such as jQuery Unobtrusive Validation,
/// to provide client validation based on the presence of these attributes.
/// </para>
/// </summary>
public interface IClientModelValidator
{
/// <summary>
/// Called to add client-side model validation.
/// </summary>
/// <param name="context">The <see cref="ClientModelValidationContext"/>.</param>
void AddValidation(ClientModelValidationContext context);
}
}

View File

@ -3,16 +3,30 @@
namespace Microsoft.AspNetCore.Mvc.ModelBinding.Validation
{
/// <summary>
/// The result of model validation.
/// </summary>
public class ModelValidationResult
{
/// <summary>
/// Initializes a new instance of <see cref="ModelValidationResult"/>.
/// </summary>
/// <param name="memberName">The name of the entry on which validation was performed.</param>
/// <param name="message">The validation message.</param>
public ModelValidationResult(string memberName, string message)
{
MemberName = memberName ?? string.Empty;
Message = message ?? string.Empty;
}
/// <summary>
/// Gets the name of the entry on which validation was performed.
/// </summary>
public string MemberName { get; }
/// <summary>
/// Gets the validation message.
/// </summary>
public string Message { get; }
}
}

View File

@ -483,6 +483,52 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
Assert.Equal(ModelValidationState.Valid, validationState);
}
[Fact]
public void GetFieldValidationState_OfSkippedEntry()
{
// Arrange
var modelState = new ModelStateDictionary();
modelState.MarkFieldSkipped("foo");
// Act
var validationState = modelState.GetValidationState("foo");
var fieldValidationState = modelState.GetFieldValidationState("foo");
// Assert
Assert.Equal(ModelValidationState.Skipped, validationState);
Assert.Equal(ModelValidationState.Valid, fieldValidationState);
}
[Fact]
public void GetFieldValidationState_WithSkippedProperty()
{
// Arrange
var modelState = new ModelStateDictionary();
modelState.MarkFieldSkipped("foo.bar.prop1");
modelState.MarkFieldValid("foo.bar.prop2");
// Act
var validationState = modelState.GetFieldValidationState("foo.bar");
// Assert
Assert.Equal(ModelValidationState.Valid, validationState);
}
[Fact]
public void GetFieldValidationState_WithAllSkippedProperties()
{
// Arrange
var modelState = new ModelStateDictionary();
modelState.MarkFieldSkipped("foo.bar.prop1");
modelState.MarkFieldSkipped("foo.bar.prop2");
// Act
var validationState = modelState.GetFieldValidationState("foo.bar");
// Assert
Assert.Equal(ModelValidationState.Valid, validationState);
}
[Fact]
public void IsValidPropertyReturnsFalse_IfSomeFieldsAreNotValidated()
{

View File

@ -83,6 +83,7 @@ namespace Microsoft.AspNetCore.Mvc.ApiExplorer
}
}
/// <inheritdoc />
public void OnProvidersExecuted(ApiDescriptionProviderContext context)
{
}

View File

@ -7,8 +7,16 @@ using Microsoft.Extensions.DependencyInjection.Extensions;
namespace Microsoft.Extensions.DependencyInjection
{
/// <summary>
/// Extensions for configuring ApiExplorer using an <see cref="IMvcCoreBuilder"/>.
/// </summary>
public static class MvcApiExplorerMvcCoreBuilderExtensions
{
/// <summary>
/// Configures <see cref="IMvcCoreBuilder"/> to use ApiExplorer.
/// </summary>
/// <param name="builder">The <see cref="IMvcCoreBuilder"/>.</param>
/// <returns>The <see cref="IMvcCoreBuilder"/>.</returns>
public static IMvcCoreBuilder AddApiExplorer(this IMvcCoreBuilder builder)
{
if (builder == null)

View File

@ -4,7 +4,6 @@
<Description>ASP.NET Core MVC API explorer functionality for discovering metadata such as the list of controllers and actions, and their URLs and allowed HTTP methods.</Description>
<TargetFramework>netcoreapp3.0</TargetFramework>
<IsAspNetCoreApp>true</IsAspNetCoreApp>
<NoWarn>$(NoWarn);CS1591</NoWarn>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageTags>aspnetcore;aspnetcoremvc</PackageTags>
</PropertyGroup>

View File

@ -53,11 +53,19 @@ namespace Microsoft.AspNetCore.Mvc
/// </summary>
public TValue Value { get; }
/// <summary>
/// Implictly converts the specified <paramref name="value"/> to an <see cref="ActionResult{TValue}"/>.
/// </summary>
/// <param name="value">The value to convert.</param>
public static implicit operator ActionResult<TValue>(TValue value)
{
return new ActionResult<TValue>(value);
}
/// <summary>
/// Implictly converts the specified <paramref name="result"/> to an <see cref="ActionResult{TValue}"/>.
/// </summary>
/// <param name="result">The <see cref="ActionResult"/>.</param>
public static implicit operator ActionResult<TValue>(ActionResult result)
{
return new ActionResult<TValue>(result);

View File

@ -13,12 +13,19 @@ namespace Microsoft.AspNetCore.Mvc.ApiExplorer
/// </summary>
public sealed class ApiConventionResult
{
/// <summary>
/// Initializes a new instance of <see cref="ApiConventionResult"/>.
/// </summary>
/// <param name="responseMetadataProviders">The sequence of <see cref="IApiResponseMetadataProvider"/> that are associated with the action.</param>
public ApiConventionResult(IReadOnlyList<IApiResponseMetadataProvider> responseMetadataProviders)
{
ResponseMetadataProviders = responseMetadataProviders ??
throw new ArgumentNullException(nameof(responseMetadataProviders));
}
/// <summary>
/// Gets the sequence of <see cref="IApiResponseMetadataProvider"/> that are associated with the action.
/// </summary>
public IReadOnlyList<IApiResponseMetadataProvider> ResponseMetadataProviders { get; }
internal static bool TryGetApiConvention(

View File

@ -17,11 +17,18 @@ namespace Microsoft.AspNetCore.Mvc.ApiExplorer
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
public sealed class ApiConventionTypeMatchAttribute : Attribute
{
/// <summary>
/// Initialzes a new instance of <see cref="ApiConventionTypeMatchAttribute"/> with the specified <paramref name="matchBehavior"/>.
/// </summary>
/// <param name="matchBehavior">The <see cref="ApiConventionTypeMatchBehavior"/>.</param>
public ApiConventionTypeMatchAttribute(ApiConventionTypeMatchBehavior matchBehavior)
{
MatchBehavior = matchBehavior;
}
/// <summary>
/// Gets the <see cref="ApiConventionTypeMatchBehavior"/>.
/// </summary>
public ApiConventionTypeMatchBehavior MatchBehavior { get; }
}
}

View File

@ -13,9 +13,17 @@ using Microsoft.Extensions.Internal;
namespace Microsoft.AspNetCore.Mvc.ApplicationModels
{
/// <summary>
/// An application model for controller actions.
/// </summary>
[DebuggerDisplay("{DisplayName}")]
public class ActionModel : ICommonModel, IFilterModel, IApiExplorerModel
{
/// <summary>
/// Initializes a new instance of <see cref="ActionModel"/>.
/// </summary>
/// <param name="actionMethod">The action <see cref="MethodInfo"/>.</param>
/// <param name="attributes">The attributes associated with the action.</param>
public ActionModel(
MethodInfo actionMethod,
IReadOnlyList<object> attributes)
@ -41,6 +49,10 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
Selectors = new List<SelectorModel>();
}
/// <summary>
/// Copy constructor for <see cref="ActionModel"/>.
/// </summary>
/// <param name="other">The <see cref="ActionModel"/> to copy.</param>
public ActionModel(ActionModel other)
{
if (other == null)
@ -67,8 +79,14 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
Selectors = new List<SelectorModel>(other.Selectors.Select(s => new SelectorModel(s)));
}
/// <summary>
/// Gets the action <see cref="MethodInfo"/>.
/// </summary>
public MethodInfo ActionMethod { get; }
/// <summary>
/// Gets the action name.
/// </summary>
public string ActionName { get; set; }
/// <summary>
@ -83,6 +101,9 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
/// </remarks>
public ApiExplorerModel ApiExplorer { get; set; }
/// <summary>
/// Gets the attributes associated with the action.
/// </summary>
public IReadOnlyList<object> Attributes { get; }
/// <summary>
@ -90,8 +111,14 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
/// </summary>
public ControllerModel Controller { get; set; }
/// <summary>
/// Gets the <see cref="IFilterMetadata"/> instances associated with the action.
/// </summary>
public IList<IFilterMetadata> Filters { get; }
/// <summary>
/// Gets the parameters associated with this action.
/// </summary>
public IList<ParameterModel> Parameters { get; }
/// <summary>
@ -144,6 +171,9 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
/// </summary>
public IList<SelectorModel> Selectors { get; }
/// <summary>
/// Gets the action display name.
/// </summary>
public string DisplayName
{
get

View File

@ -34,6 +34,7 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
/// </summary>
public ProducesErrorResponseTypeAttribute DefaultErrorResponseType { get; }
/// <inheritdoc />
public void Apply(ActionModel action)
{
if (action == null)
@ -50,6 +51,14 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
DiscoverErrorResponseType(action);
}
/// <summary>
/// Determines if this instance of <see cref="IActionModelConvention"/> applies to a specified <paramref name="action"/>.
/// </summary>
/// <param name="action">The <see cref="ActionModel"/>.</param>
/// <returns>
/// <see langword="true"/> if the convention applies, otherwise <see langword="false"/>.
/// Derived types may override this method to selectively apply this convention.
/// </returns>
protected virtual bool ShouldApply(ActionModel action) => true;
private static void DiscoverApiConvention(ActionModel action)

View File

@ -8,6 +8,7 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
/// </summary>
public class ApiVisibilityConvention : IActionModelConvention
{
/// <inheritdoc />
public void Apply(ActionModel action)
{
if (!ShouldApply(action))
@ -22,6 +23,14 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
}
}
/// <summary>
/// Determines if this instance of <see cref="IActionModelConvention"/> applies to a specified <paramref name="action"/>.
/// </summary>
/// <param name="action">The <see cref="ActionModel"/>.</param>
/// <returns>
/// <see langword="true"/> if the convention applies, otherwise <see langword="false"/>.
/// Derived types may override this method to selectively apply this convention.
/// </returns>
protected virtual bool ShouldApply(ActionModel action) => true;
}
}

View File

@ -7,9 +7,15 @@ using Microsoft.AspNetCore.Mvc.Filters;
namespace Microsoft.AspNetCore.Mvc.ApplicationModels
{
/// <summary>
/// A model for configuring controllers in an MVC application.
/// </summary>
[DebuggerDisplay("ApplicationModel: Controllers: {Controllers.Count}, Filters: {Filters.Count}")]
public class ApplicationModel : IPropertyModel, IFilterModel, IApiExplorerModel
{
/// <summary>
/// Initializes a new instance of <see cref="ApplicationModel"/>.
/// </summary>
public ApplicationModel()
{
ApiExplorer = new ApiExplorerModel();
@ -31,8 +37,14 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
/// </remarks>
public ApiExplorerModel ApiExplorer { get; set; }
/// <summary>
/// Gets the <see cref="ControllerModel"/> instances.
/// </summary>
public IList<ControllerModel> Controllers { get; }
/// <summary>
/// Gets the global <see cref="IFilterMetadata"/> instances.
/// </summary>
public IList<IFilterMetadata> Filters { get; }
/// <summary>

View File

@ -12,6 +12,10 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
/// </summary>
public class ApplicationModelProviderContext
{
/// <summary>
/// Initializes a new instance of <see cref="ApplicationModelProviderContext"/>.
/// </summary>
/// <param name="controllerTypes">The discovered controller <see cref="TypeInfo"/> instances.</param>
public ApplicationModelProviderContext(IEnumerable<TypeInfo> controllerTypes)
{
if (controllerTypes == null)
@ -22,6 +26,9 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
ControllerTypes = controllerTypes;
}
/// <summary>
/// Gets the discovered controller <see cref="TypeInfo"/> instances.
/// </summary>
public IEnumerable<TypeInfo> ControllerTypes { get; }
/// <summary>

View File

@ -11,14 +11,24 @@ using Microsoft.AspNetCore.Routing;
namespace Microsoft.AspNetCore.Mvc.ApplicationModels
{
/// <summary>
/// A model for attribute routes.
/// </summary>
public class AttributeRouteModel
{
private static readonly AttributeRouteModel _default = new AttributeRouteModel();
/// <summary>
/// Initializes a new instance of <see cref="AttributeRoute"/>.
/// </summary>
public AttributeRouteModel()
{
}
/// <summary>
/// Initializes a new instance of <see cref="AttributeRoute"/> using the specified <paramref name="templateProvider"/>.
/// </summary>
/// <param name="templateProvider">The <see cref="IRouteTemplateProvider"/>.</param>
public AttributeRouteModel(IRouteTemplateProvider templateProvider)
{
if (templateProvider == null)
@ -32,6 +42,10 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
Name = templateProvider.Name;
}
/// <summary>
/// Copy constructor for <see cref="AttributeRoute"/>.
/// </summary>
/// <param name="other">The <see cref="AttributeRouteModel"/> to copy.</param>
public AttributeRouteModel(AttributeRouteModel other)
{
if (other == null)
@ -47,12 +61,24 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
SuppressPathMatching = other.SuppressPathMatching;
}
public IRouteTemplateProvider Attribute { get;}
/// <summary>
/// Gets the <see cref="IRouteTemplateProvider"/>.
/// </summary>
public IRouteTemplateProvider Attribute { get; }
/// <summary>
/// Gets or sets the attribute route template.
/// </summary>
public string Template { get; set; }
/// <summary>
/// Gets or sets the route order.
/// </summary>
public int? Order { get; set; }
/// <summary>
/// Gets or sets the route name.
/// </summary>
public string Name { get; set; }
/// <summary>
@ -65,6 +91,9 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
/// </summary>
public bool SuppressPathMatching { get; set; }
/// <summary>
/// Gets or sets a value that determines if this route template for this model overrides the route template at the parent scope.
/// </summary>
public bool IsAbsoluteTemplate => Template != null && IsOverridePattern(Template);
/// <summary>

View File

@ -15,6 +15,7 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
{
private readonly ClientErrorResultFilterFactory _filterFactory = new ClientErrorResultFilterFactory();
/// <inheritdoc />
public void Apply(ActionModel action)
{
if (action == null)
@ -31,6 +32,14 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
action.Filters.Add(_filterFactory);
}
/// <summary>
/// Determines if this instance of <see cref="IActionModelConvention"/> applies to a specified <paramref name="action"/>.
/// </summary>
/// <param name="action">The <see cref="ActionModel"/>.</param>
/// <returns>
/// <see langword="true"/> if the convention applies, otherwise <see langword="false"/>.
/// Derived types may override this method to selectively apply this convention.
/// </returns>
protected virtual bool ShouldApply(ActionModel action) => true;
}
}

View File

@ -14,6 +14,7 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
/// </summary>
public class ConsumesConstraintForFormFileParameterConvention : IActionModelConvention
{
/// <inheritdoc />
public void Apply(ActionModel action)
{
if (action == null)
@ -29,6 +30,14 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
AddMultipartFormDataConsumesAttribute(action);
}
/// <summary>
/// Determines if this instance of <see cref="IActionModelConvention"/> applies to a specified <paramref name="action"/>.
/// </summary>
/// <param name="action">The <see cref="ActionModel"/>.</param>
/// <returns>
/// <see langword="true"/> if the convention applies, otherwise <see langword="false"/>.
/// Derived types may override this method to selectively apply this convention.
/// </returns>
protected virtual bool ShouldApply(ActionModel action) => true;
// Internal for unit testing

View File

@ -42,6 +42,12 @@ namespace Microsoft.Extensions.DependencyInjection
return builder;
}
/// <summary>
/// Configures <see cref="FormatterMappings"/> for the specified <paramref name="builder"/>.
/// </summary>
/// <param name="builder">The <see cref="IMvcBuilder"/>.</param>
/// <param name="setupAction">An <see cref="Action"/> to configure the <see cref="FormatterMappings"/>.</param>
/// <returns>The <see cref="IMvcBuilder"/>.</returns>
public static IMvcBuilder AddFormatterMappings(
this IMvcBuilder builder,
Action<FormatterMappings> setupAction)

View File

@ -15,6 +15,9 @@ using Microsoft.Extensions.DependencyInjection.Extensions;
namespace Microsoft.Extensions.DependencyInjection
{
/// <summary>
/// Extensions for configuring MVC using an <see cref="IMvcCoreBuilder"/>.
/// </summary>
public static class MvcCoreMvcCoreBuilderExtensions
{
/// <summary>
@ -41,12 +44,23 @@ namespace Microsoft.Extensions.DependencyInjection
return builder;
}
/// <summary>
/// Adds services to support <see cref="FormatterMappings"/>.
/// </summary>
/// <param name="builder">The <see cref="IMvcBuilder"/>.</param>
/// <returns>The <see cref="IMvcBuilder"/>.</returns>
public static IMvcCoreBuilder AddFormatterMappings(this IMvcCoreBuilder builder)
{
AddFormatterMappingsServices(builder.Services);
return builder;
}
/// <summary>
/// Configures <see cref="FormatterMappings"/> for the specified <paramref name="setupAction"/>.
/// </summary>
/// <param name="builder">The <see cref="IMvcCoreBuilder"/>.</param>
/// <param name="setupAction">An <see cref="Action"/> to configure the <see cref="FormatterMappings"/>.</param>
/// <returns>The <see cref="IMvcBuilder"/>.</returns>
public static IMvcCoreBuilder AddFormatterMappings(
this IMvcCoreBuilder builder,
Action<FormatterMappings> setupAction)
@ -67,12 +81,23 @@ namespace Microsoft.Extensions.DependencyInjection
services.TryAddSingleton<FormatFilter, FormatFilter>();
}
/// <summary>
/// Configures authentication and authorization services for <paramref name="builder"/>.
/// </summary>
/// <param name="builder">The <see cref="IMvcCoreBuilder"/>.</param>
/// <returns>The <see cref="IMvcCoreBuilder"/>.</returns>
public static IMvcCoreBuilder AddAuthorization(this IMvcCoreBuilder builder)
{
AddAuthorizationServices(builder.Services);
return builder;
}
/// <summary>
/// Configures authentication and authorization services for <paramref name="builder"/>.
/// </summary>
/// <param name="builder">The <see cref="IMvcCoreBuilder"/>.</param>
/// <param name="setupAction">An <see cref="Action"/> to configure the <see cref="AuthorizationOptions"/>.</param>
/// <returns>The <see cref="IMvcCoreBuilder"/>.</returns>
public static IMvcCoreBuilder AddAuthorization(
this IMvcCoreBuilder builder,
Action<AuthorizationOptions> setupAction)

View File

@ -9,8 +9,16 @@ using Microsoft.Extensions.DependencyInjection.Extensions;
namespace Microsoft.Extensions.DependencyInjection
{
/// <summary>
/// Extensions for configuring CORS using an <see cref="IMvcCoreBuilder"/>.
/// </summary>
public static class MvcCorsMvcCoreBuilderExtensions
{
/// <summary>
/// Configures <see cref="IMvcCoreBuilder"/> to use CORS.
/// </summary>
/// <param name="builder">The <see cref="IMvcCoreBuilder"/>.</param>
/// <returns>The <see cref="IMvcCoreBuilder"/>.</returns>
public static IMvcCoreBuilder AddCors(this IMvcCoreBuilder builder)
{
if (builder == null)
@ -22,6 +30,12 @@ namespace Microsoft.Extensions.DependencyInjection
return builder;
}
/// <summary>
/// Configures <see cref="IMvcCoreBuilder"/> to use CORS.
/// </summary>
/// <param name="builder">The <see cref="IMvcCoreBuilder"/>.</param>
/// <param name="setupAction">An <see cref="Action{MvcOptions}"/> to configure the provided <see cref="CorsOptions"/>.</param>
/// <returns>The <see cref="IMvcCoreBuilder"/>.</returns>
public static IMvcCoreBuilder AddCors(
this IMvcCoreBuilder builder,
Action<CorsOptions> setupAction)
@ -42,6 +56,12 @@ namespace Microsoft.Extensions.DependencyInjection
return builder;
}
/// <summary>
/// Configures <see cref="CorsOptions"/>.
/// </summary>
/// <param name="builder">The <see cref="IMvcCoreBuilder"/>.</param>
/// <param name="setupAction">The configure action.</param>
/// <returns>The <see cref="IMvcCoreBuilder"/>.</returns>
public static IMvcCoreBuilder ConfigureCors(
this IMvcCoreBuilder builder,
Action<CorsOptions> setupAction)

View File

@ -4,7 +4,6 @@
<Description>ASP.NET Core MVC cross-origin resource sharing (CORS) features.</Description>
<TargetFramework>netcoreapp3.0</TargetFramework>
<IsAspNetCoreApp>true</IsAspNetCoreApp>
<NoWarn>$(NoWarn);CS1591</NoWarn>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageTags>aspnetcore;aspnetcoremvc;cors</PackageTags>
</PropertyGroup>

View File

@ -4,7 +4,6 @@
<Description>ASP.NET Core MVC metadata and validation system using System.ComponentModel.DataAnnotations.</Description>
<TargetFramework>netcoreapp3.0</TargetFramework>
<IsAspNetCoreApp>true</IsAspNetCoreApp>
<NoWarn>$(NoWarn);CS1591</NoWarn>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageTags>aspnetcore;aspnetcoremvc</PackageTags>
</PropertyGroup>

View File

@ -7,7 +7,6 @@ Microsoft.AspNetCore.Mvc.Localization.IHtmlLocalizer&lt;TResource&gt;
Microsoft.AspNetCore.Mvc.Localization.IViewLocalizer</Description>
<TargetFramework>netcoreapp3.0</TargetFramework>
<IsAspNetCoreApp>true</IsAspNetCoreApp>
<NoWarn>$(NoWarn);CS1591</NoWarn>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageTags>aspnetcore;aspnetcoremvc;localization</PackageTags>
</PropertyGroup>

View File

@ -3,7 +3,6 @@
<PropertyGroup>
<Description>ASP.NET Core MVC features that use Newtonsoft.Json. Includes input and output formatters for JSON and JSON PATCH.</Description>
<TargetFramework>netcoreapp3.0</TargetFramework>
<NoWarn>$(NoWarn);CS1591</NoWarn>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageTags>aspnetcore;aspnetcoremvc;json</PackageTags>
<IsShippingPackage>true</IsShippingPackage>

View File

@ -3,7 +3,6 @@
<PropertyGroup>
<Description>ASP.NET Core MVC is a web framework that gives you a powerful, patterns-based way to build dynamic websites and web APIs. ASP.NET Core MVC enables a clean separation of concerns and gives you full control over markup.</Description>
<TargetFramework>netcoreapp3.0</TargetFramework>
<NoWarn>$(NoWarn);CS1591</NoWarn>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageTags>aspnetcore;aspnetcoremvc</PackageTags>
<IsAspNetCoreApp>true</IsAspNetCoreApp>