| File: RouteOptions.cs | Web Access |
| Project: src\aspnetcore\src\Http\Routing\src\Microsoft.AspNetCore.Routing.csproj (Microsoft.AspNetCore.Routing) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. #if !COMPONENTS using System.Diagnostics; #else using Microsoft.AspNetCore.Components.Routing; #endif using System.Diagnostics.CodeAnalysis; using Microsoft.AspNetCore.Routing.Constraints; namespace Microsoft.AspNetCore.Routing; #if !COMPONENTS /// <summary> /// Represents the configurable options on a route. /// </summary> public class RouteOptions #else internal class RouteOptions #endif { private IDictionary<string, Type> _constraintTypeMap = GetDefaultConstraintMap(); #if !COMPONENTS private ICollection<EndpointDataSource> _endpointDataSources = default!; /// <summary> /// Gets a collection of <see cref="EndpointDataSource"/> instances configured with routing. /// </summary> internal ICollection<EndpointDataSource> EndpointDataSources { get { Debug.Assert(_endpointDataSources != null, "Endpoint data sources should have been set in DI."); return _endpointDataSources; } set => _endpointDataSources = value; } /// <summary> /// Gets or sets a value indicating whether all generated paths URLs are lowercase. /// Use <see cref="LowercaseQueryStrings" /> to configure the behavior for query strings. /// </summary> public bool LowercaseUrls { get; set; } /// <summary> /// Gets or sets a value indicating whether a generated query strings are lowercase. /// This property will not be used unless <see cref="LowercaseUrls" /> is also <c>true</c>. /// </summary> public bool LowercaseQueryStrings { get; set; } /// <summary> /// Gets or sets a value indicating whether a trailing slash should be appended to the generated URLs. /// </summary> public bool AppendTrailingSlash { get; set; } /// <summary> /// Gets or sets a value that indicates if the check for unhandled security endpoint metadata is suppressed. /// <para> /// Endpoints can be associated with metadata such as authorization, or CORS, that needs to be /// handled by a specific middleware to be actionable. If the middleware is not configured, such /// metadata will go unhandled. /// </para> /// <para> /// When <see langword="false"/>, prior to the execution of the endpoint, routing will verify that /// all known security-specific metadata has been handled. /// Setting this property to <see langword="true"/> suppresses this check. /// </para> /// </summary> /// <value>Defaults to <see langword="false"/>.</value> /// <remarks> /// This check exists as a safeguard against accidental insecure configuration. You may suppress /// this check if it does not match your application's requirements. /// </remarks> public bool SuppressCheckForUnhandledSecurityMetadata { get; set; } #endif /// <summary> /// Gets or sets a collection of constraints on the current route. /// </summary> public IDictionary<string, Type> ConstraintMap { [RequiresUnreferencedCode($"The linker cannot determine what constraints are being added via the ConstraintMap property. Prefer {nameof(RouteOptions)}.{nameof(SetParameterPolicy)} instead for setting constraints. This warning can be suppressed if this property is being used to read or delete constraints.")] get { return _constraintTypeMap; } set { ArgumentNullException.ThrowIfNull(value); _constraintTypeMap = value; } } /// <summary> /// <see cref="SetParameterPolicy{T}(string)"/> ensures that types are added to the constraint map in a trimmer safe way. /// This API allows reading the map without encountering a trimmer warning within the framework. /// </summary> internal IDictionary<string, Type> TrimmerSafeConstraintMap => _constraintTypeMap; private static IDictionary<string, Type> GetDefaultConstraintMap() { var defaults = new Dictionary<string, Type>(StringComparer.OrdinalIgnoreCase); // Type-specific constraints AddConstraint<IntRouteConstraint>(defaults, "int"); AddConstraint<BoolRouteConstraint>(defaults, "bool"); AddConstraint<DateTimeRouteConstraint>(defaults, "datetime"); AddConstraint<DecimalRouteConstraint>(defaults, "decimal"); AddConstraint<DoubleRouteConstraint>(defaults, "double"); AddConstraint<FloatRouteConstraint>(defaults, "float"); AddConstraint<GuidRouteConstraint>(defaults, "guid"); AddConstraint<LongRouteConstraint>(defaults, "long"); // Length constraints AddConstraint<MinLengthRouteConstraint>(defaults, "minlength"); AddConstraint<MaxLengthRouteConstraint>(defaults, "maxlength"); AddConstraint<LengthRouteConstraint>(defaults, "length"); // Min/Max value constraints AddConstraint<MinRouteConstraint>(defaults, "min"); AddConstraint<MaxRouteConstraint>(defaults, "max"); AddConstraint<RangeRouteConstraint>(defaults, "range"); // The alpha constraint uses a compiled regex which has a minimal size cost. AddConstraint<AlphaRouteConstraint>(defaults, "alpha"); #if !COMPONENTS AddConstraint<RegexErrorStubRouteConstraint>(defaults, "regex"); // Used to generate error message at runtime with helpful message. AddConstraint<RequiredRouteConstraint>(defaults, "required"); #else // Check if the feature is not enabled in the browser context if (OperatingSystem.IsBrowser() && !RegexConstraintSupport.IsEnabled) { AddConstraint<RegexErrorStubRouteConstraint>(defaults, "regex"); // Used to generate error message at runtime with helpful message. } #endif // Files AddConstraint<FileNameRouteConstraint>(defaults, "file"); AddConstraint<NonFileNameRouteConstraint>(defaults, "nonfile"); return defaults; } /// <summary> /// Adds or overwrites the parameter policy with the associated route pattern token. /// </summary> /// <typeparam name="T">The parameter policy type.</typeparam> /// <param name="token">The route token used to apply the parameter policy.</param> public void SetParameterPolicy<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] T>(string token) where T : IParameterPolicy { _constraintTypeMap[token] = typeof(T); } /// <summary> /// Adds or overwrites the parameter policy with the associated route pattern token. /// </summary> /// <param name="token">The route token used to apply the parameter policy.</param> /// <param name="type">The parameter policy type.</param> /// <exception cref="InvalidOperationException">Throws an exception if the type is not an <see cref="IParameterPolicy"/>.</exception> public void SetParameterPolicy(string token, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type type) { if (!type.IsAssignableTo(typeof(IParameterPolicy))) { throw new InvalidOperationException($"{type} must implement {typeof(IParameterPolicy)}"); } _constraintTypeMap[token] = type; } private static void AddConstraint<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TConstraint>(Dictionary<string, Type> constraintMap, string text) where TConstraint : IRouteConstraint { constraintMap[text] = typeof(TConstraint); } }